From d2e7ea0b6861416b16969f673487b0c59154537f Mon Sep 17 00:00:00 2001 From: Cary R Date: Thu, 15 Jan 2009 10:43:46 -0800 Subject: [PATCH] Convert $monitor to use string based formatting. This completes the transition to the new string based formatting. All the tasks now use the string formatting routines. Better compile time checking and better messages were also added. Also a couple of types were added to vpi_get_str(vpiType, ...) and the calculation for vpiConstantSelect was fixed for both the &A<> and &PV<> constructs. If the value is a plain variable or if it is calculated in thread space we assume it is not a constant. This may not be true because of limitations/bugs in the compiler (constant user functions are one known problem). --- vpi/sys_display.c | 1309 ++++++++++----------------------------------- vvp/array.cc | 9 +- vvp/vpi_priv.cc | 4 + vvp/vpi_signal.cc | 5 +- 4 files changed, 310 insertions(+), 1017 deletions(-) diff --git a/vpi/sys_display.c b/vpi/sys_display.c index c17ac5c0c..b727ee4fc 100644 --- a/vpi/sys_display.c +++ b/vpi/sys_display.c @@ -131,774 +131,6 @@ static void array_from_iterator(struct strobe_cb_info*info, vpiHandle argv) } } -/* - * This function writes the time value into the mcd target with the - * proper format. The mcd is the destination file. - * - * The fsize is the width of the field to use. Normally, this is -1 to - * reflect the format string "%t". It may also be 0 for the format - * string "%0t". This formatter also allows for the nonstandard use of - * positive values to enforce a width to override the width given in - * the $timeformat system task. - * - * The value argument is the time value as a decimal string. There are - * no leading zeros in this string, and the units of the value are - * given in the units argument. - */ -static void format_time(unsigned mcd, int fsize, - const char*value, int time_units) -{ - char buf[256]; - const char*cp; - char*bp, *start_address; - - int idx; - unsigned int fusize; - int fraction_chars, fraction_pad, value_chop, whole_fill; - - /* This is the format precision expressed as the power of 10 - of the desired precision. The following code uses this - format to be consistent with the units specifications. */ - int format_precision = timeformat_info.units - timeformat_info.prec; - - /* If the fsize is <0, then use the value from the - $timeformat. If the fsize is >=0, then it overrides the - $timeformat value. */ - fusize = (fsize<0) ? timeformat_info.width : (unsigned) fsize; - - assert(fusize < (sizeof buf - 1)); - - - /* This is the number of characters to the right of the - decimal point. This is defined completely by the - timeformat. It is legal for the precision to be larger then - the units, and in this case there will be no fraction_chars - at all. */ - fraction_chars = timeformat_info.units - format_precision; - if (fraction_chars < 0) - fraction_chars = 0; - - /* This is the number of zeros I must add to the value to get - the desired precision within the fraction. If this value is - greater than 0, the value does not have enough characters, - so I will be adding zeros. */ - - fraction_pad = time_units - format_precision; - if (fraction_pad < 0) - fraction_pad = 0; - if (fraction_pad > fraction_chars) - fraction_pad = fraction_chars; - - - /* This is the number of characters of excess precision in the - supplied value. This many characters are chopped from the - least significant end. */ - value_chop = format_precision - time_units; - if (value_chop < 0) - value_chop = 0; - - /* This is the number of zeros that I must add to the integer - part of the output string to pad the value out to the - desired units. This will only have a non-zero value if the - units of the value is greater than the desired units. - - Detect the special case where the value is 0. In this case, - do not do any integer filling ever. The output should be - padded with blanks in that case. */ - whole_fill = time_units - timeformat_info.units; - if (whole_fill < 0) - whole_fill = 0; - if (strcmp(value,"0") == 0) - whole_fill = 0; - - /* This is the expected start address of the output. It - accounts for the f(u)size value that is chosen. The output - will be filled out to complete the buffer. */ - if (fusize == 0) - start_address = buf; - else - start_address = buf + sizeof buf - fusize - 1; - - /* Now start the character pointers, ready to start copying - the value into the format. */ - cp = value + strlen(value); - if (value_chop > (cp - value)) - cp = value; - else - cp -= value_chop; - - bp = buf + sizeof buf; - *--bp = 0; - - - /* Write the suffix. */ - bp -= strlen(timeformat_info.suff); - strcpy(bp, timeformat_info.suff); - - /* Write the padding needed to fill out the fraction. */ - for (idx = 0 ; idx < fraction_pad ; idx += 1) - *--bp = '0'; - - /* Subtract the pad from the needed chars. */ - assert(fraction_pad <= fraction_chars); - fraction_chars -= fraction_pad; - fraction_pad = 0; - - /* Write the fraction chars. */ - for (idx = 0 ; idx < fraction_chars ; idx += 1) { - if (cp > value) - *--bp = *--cp; - else - *--bp = '0'; - - assert(cp >= value); - } - - /* Write the decimal point, if needed. */ - if (timeformat_info.prec > 0) - *--bp = '.'; - - /* Fill the gap between the value and the decimal point. */ - for (idx = 0 ; idx < whole_fill ; idx += 1) - *--bp = '0'; - - /* Write the integer part of the value. */ - while (cp > value) { - *--bp = *--cp; - } - - /* Fill the leading characters to make up the desired - width. This may require a '0' if the last character - written was the decimal point. This may also require a '0' - if there are no other characters at all in the output. */ - if (fusize > 0) { - while (bp > start_address) { - if (*bp == '.' || strcmp(bp, timeformat_info.suff) == 0) - *--bp = '0'; - else - *--bp = ' '; - } - } else { - if (*bp == '.' || strcmp(bp, timeformat_info.suff) == 0) - *--bp = '0'; - } - - - my_mcd_printf(mcd, "%s", bp); -} - -static void format_time_real(unsigned mcd, int fsize, - double value, int time_units) -{ - int width; - - /* The time_units is the units of the current scope, and also - of the value. If the scope units are different from the - format specifier units, then scale the value. */ - if (time_units != timeformat_info.units) - value *= pow(10.0, time_units - timeformat_info.units); - - if (fsize == -1) { - width = timeformat_info.width - strlen(timeformat_info.suff); - } else { - width = fsize; - } - /* The timeformat_info.prec is the number of digits after the - decimal point, no matter what the units. */ - my_mcd_printf(mcd, "%*.*f%s", width, timeformat_info.prec, value, - timeformat_info.suff); -} - - -static void format_strength(unsigned int mcd, s_vpi_value*value, - unsigned size) -{ - char str[4]; - int bit; - - for (bit = size-1; bit >= 0; bit -= 1) { - vpip_format_strength(str, value, (unsigned) bit); - my_mcd_printf(mcd, "%s", str); - if (bit > 0) my_mcd_printf(mcd, "_"); - } -} - -static void format_error_msg(const char*msg, int leading_zero, - int fsize, int ffsize, char fmt) -{ - if ((fsize < 0) && (ffsize < 0)) { - if (leading_zero > 0) - vpi_printf("\nERROR: %s: %%0%c\n", msg, fmt); - else - vpi_printf("\nERROR: %s: %%%c\n", msg, fmt); - - } else if (ffsize < 0) { - if ((leading_zero > 0) && (fsize > 0)) - vpi_printf("\nERROR: %s: %%0%d%c\n", msg, - fsize, fmt); - else - vpi_printf("\nERROR: %s: %%%d%c\n", msg, - fsize, fmt); - - } else { - vpi_printf("\nERROR: %s: %%%d.%d%c\n", msg, - fsize, ffsize, fmt); - } -} - -/* - * The format_str uses this function to do the special job of - * interpreting the next item depending on the format code. The caller - * has already parsed the %x.yf format string. - * - * The return code is the number of arguments that were consumed. - */ -static int format_str_char(vpiHandle scope, unsigned int mcd, - int leading_zero, int fsize, int ffsize, - char fmt, int argc, vpiHandle*argv, int idx) -{ - s_vpi_value value; - int use_count = 0; - - /* Time units of the current scope. */ - int time_units = vpi_get(vpiTimeUnit, scope); - - switch (fmt) { - - case 0: - return 0; - - case '%': - if (fsize != -1 && ffsize != -1) { - format_error_msg("Illegal format", leading_zero, - fsize, ffsize, fmt); - fsize = -1; - ffsize = -1; - } - - my_mcd_printf(mcd, "%%"); - - use_count = 0; - break; - - /* new Verilog 2001 format specifiers... */ - case 'l': - case 'L': - case 'u': - case 'U': - case 'z': - case 'Z': - format_error_msg("Unsupported format", leading_zero, - fsize, ffsize, fmt); - my_mcd_printf(mcd, "%c", fmt); - - use_count = 0; - break; - - default: - format_error_msg("Illegal format", leading_zero, - fsize, ffsize, fmt); - my_mcd_printf(mcd, "%c", fmt); - break; - - /* Print numeric value in binary/hex/octal format. */ - case 'b': - case 'B': - case 'h': - case 'H': - case 'o': - case 'O': - case 'x': - case 'X': - if (ffsize != -1) { - format_error_msg("Illegal format", leading_zero, - fsize, ffsize, fmt); - fsize = -1; - } - - if (idx >= argc) { - format_error_msg("Missing Argument", leading_zero, - fsize, ffsize, fmt); - return 0; - } - - switch (fmt) { - case 'b': - case 'B': - value.format = vpiBinStrVal; - break; - case 'h': - case 'H': - case 'x': - case 'X': - value.format = vpiHexStrVal; - break; - case 'o': - case 'O': - value.format = vpiOctStrVal; - break; - } - - vpi_get_value(argv[idx], &value); - if (value.format == vpiSuppressVal){ - format_error_msg("Incompatible value", leading_zero, - fsize, ffsize, fmt); - return 1; - } - - { char* value_str = value.value.str; - if (leading_zero==1){ - /* Strip away all leading zeros from string */ - unsigned int i=0; - while(i< (strlen(value_str)-1) && value_str[i]=='0') - i++; - value_str += i; - } - - my_mcd_printf(mcd, "%*s", fsize, value_str); - } - - use_count = 1; - break; - - /* Print character */ - case 'c': - case 'C': - if (fsize != -1 && ffsize != -1) { - format_error_msg("Illegal format", leading_zero, - fsize, ffsize, fmt); - fsize = -1; - ffsize = -1; - } - - if (idx >= argc) { - format_error_msg("Missing Argument", leading_zero, - fsize, ffsize, fmt); - return 0; - } - - value.format = vpiStringVal; - vpi_get_value(argv[idx], &value); - if (value.format == vpiSuppressVal){ - format_error_msg("Incompatible value", leading_zero, - fsize, ffsize, fmt); - return 1; - } - - my_mcd_printf(mcd, "%c", value.value.str[strlen(value.value.str)-1]); - - use_count = 1; - break; - - /* Print numeric value is decimal integer format. */ - case 'd': - case 'D': - if (ffsize != -1) { - format_error_msg("Illegal format", leading_zero, - fsize, ffsize, fmt); - fsize = -1; - } - - if (idx >= argc) { - format_error_msg("Missing Argument", leading_zero, - fsize, ffsize, fmt); - return 0; - } - - value.format = vpiDecStrVal; - vpi_get_value(argv[idx], &value); - if (value.format == vpiSuppressVal){ - format_error_msg("Incompatible value", leading_zero, - fsize, ffsize, fmt); - return 1; - } - - char *res_val_str; - if (fsize==-1){ - /* simple %d parameter, or %0d parameter. - * Size is now determined by the width - * of the vector or integer. If %0d, then - * set the size to 0 so that the minimum - * size is used. - */ - fsize = (leading_zero==1) - ? 0 - : vpi_get_dec_size(argv[idx]); - res_val_str = strdup(value.value.str); - } else { - if(leading_zero == 1){ - // case of '%04d' - padding with zeros - int abs_fsize = abs(fsize); - int res_val_str_len, res_val_str_indx=0, val_indx=0; - res_val_str_len = (strlen(value.value.str) > abs_fsize ? strlen(value.value.str) : abs_fsize) + 2; - res_val_str = malloc(sizeof(char)*res_val_str_len); - assert(res_val_str); - if(value.value.str[0] == '-'){ - res_val_str[res_val_str_indx++] = '-'; - val_indx++; - } - // padding with zeros (if required) - if(abs_fsize > strlen(value.value.str)) { - memset(&res_val_str[res_val_str_indx], '0', abs_fsize-strlen(value.value.str)); - res_val_str_indx += abs_fsize-strlen(value.value.str); - } - // copy rest of the value - strcpy(&res_val_str[res_val_str_indx], &value.value.str[val_indx]); - } else { - // case of '%4d' - res_val_str = strdup(value.value.str); - } - } - - my_mcd_printf(mcd, "%*s", fsize, res_val_str); - free(res_val_str); - - use_count = 1; - break; - - case 'e': - case 'E': - if (idx >= argc) { - format_error_msg("Missing Argument", leading_zero, - fsize, ffsize, fmt); - return 0; - } - - value.format = vpiRealVal; - vpi_get_value(argv[idx], &value); - if (value.format == vpiSuppressVal){ - format_error_msg("Incompatible value", leading_zero, - fsize, ffsize, fmt); - return 1; - } - - if (fmt == 'e') - my_mcd_printf(mcd, "%*.*e", fsize, ffsize, value.value.real); - else - my_mcd_printf(mcd, "%*.*E", fsize, ffsize, value.value.real); - - use_count = 1; - break; - - case 'f': - case 'F': - if (idx >= argc) { - format_error_msg("Missing Argument", leading_zero, - fsize, ffsize, fmt); - return 0; - } - - value.format = vpiRealVal; - vpi_get_value(argv[idx], &value); - if (value.format == vpiSuppressVal){ - format_error_msg("Incompatible value", leading_zero, - fsize, ffsize, fmt); - return 1; - } - - my_mcd_printf(mcd, "%*.*f", fsize, ffsize, value.value.real); - - use_count = 1; - break; - - case 'g': - case 'G': - if (idx >= argc) { - format_error_msg("Missing Argument", leading_zero, - fsize, ffsize, fmt); - return 0; - } - - value.format = vpiRealVal; - vpi_get_value(argv[idx], &value); - if (value.format == vpiSuppressVal){ - format_error_msg("Incompatible value", leading_zero, - fsize, ffsize, fmt); - return 1; - } - - if (fmt == 'g') - my_mcd_printf(mcd, "%*.*g", fsize, ffsize, value.value.real); - else - my_mcd_printf(mcd, "%*.*G", fsize, ffsize, value.value.real); - - use_count = 1; - break; - - /* Print the current scope. */ - case 'm': - case 'M': - if (ffsize != -1) { - format_error_msg("Illegal format", leading_zero, - fsize, ffsize, fmt); - fsize = -1; - } - if (fsize == -1) - fsize = 0; - assert(scope); - my_mcd_printf(mcd, "%*s", - fsize, - vpi_get_str(vpiFullName, scope)); - break; - - - /* Print vector as a string value. */ - case 's': - case 'S': - if (ffsize != -1) { - format_error_msg("Illegal format", leading_zero, - fsize, ffsize, fmt); - fsize = -1; - } - - value.format = vpiStringVal; - vpi_get_value(argv[idx], &value); - if (value.format == vpiSuppressVal){ - format_error_msg("Incompatible value", leading_zero, - fsize, ffsize, fmt); - return 1; - } - - if (fsize==-1){ - fsize = (vpi_get(vpiSize, argv[idx]) + 7) / 8; - my_mcd_printf(mcd, "%*s", fsize, value.value.str); - - } else { - char* value_str = value.value.str; - my_mcd_printf(mcd, "%*s", fsize, value_str); - } - - use_count = 1; - break; - - case 't': - case 'T': - if (ffsize != -1) { - format_error_msg("Illegal format", leading_zero, - fsize, ffsize, fmt); - fsize = -1; - } - - if (idx >= argc) { - format_error_msg("Missing Argument", leading_zero, - fsize, ffsize, fmt); - return 0; - } - - if (is_constant_obj(argv[idx]) - && (vpi_get(vpiConstType, argv[idx]) == vpiRealConst)) { - - value.format = vpiRealVal; - vpi_get_value(argv[idx], &value); - format_time_real(mcd, fsize, value.value.real, time_units); - - } else { - - value.format = vpiDecStrVal; - vpi_get_value(argv[idx], &value); - if (value.format == vpiSuppressVal){ - format_error_msg("Incompatible value", leading_zero, - fsize, ffsize, fmt); - return 1; - } - - format_time(mcd, fsize, value.value.str, time_units); - } - - use_count = 1; - break; - - case 'v': - case 'V': - value.format = vpiStrengthVal; - vpi_get_value(argv[idx], &value); - if (value.format == vpiSuppressVal){ - format_error_msg("Incompatible value", leading_zero, - fsize, ffsize, fmt); - return 1; - } - - format_strength(mcd, &value, vpi_get(vpiSize, argv[idx])); - - use_count = 1; - break; - - } - - return use_count; -} - -/* - * If $display discovers a string as a parameter, this function is - * called to process it as a format string. I need the argv handle as - * well so that I can look for arguments as I move forward through the - * string. - */ -static int format_str(vpiHandle scope, unsigned int mcd, - char*format, int argc, vpiHandle*argv) -{ - char buf[256], fmt[256]; - char*cp = fmt; - int idx; - - assert(format); - - /* - * Copy format out of value buffer since it will be - * clobbered by successive vpi_get_value() calls. - */ - strncpy(fmt, format, sizeof fmt - 1); - fmt[sizeof fmt - 1] = 0; - - idx = 0; - - while (*cp) { - size_t cnt = strcspn(cp, "%"); - if (cnt > 0) { - /* String of not-escape characters... */ - if (cnt >= sizeof buf) - cnt = sizeof buf - 1; - strncpy(buf, cp, cnt); - buf[cnt] = 0; - my_mcd_printf(mcd, "%s", buf); - cp += cnt; - - } else { - int leading_zero = -1, ljust = 1, fsize = -1, ffsize = -1; - - assert(*cp == '%'); - cp += 1; - if (*cp == '-') { - ljust=-1; - cp += 1; - } - if (*cp == '0') - leading_zero=1; - if (isdigit((int)*cp)) - fsize = ljust * strtoul(cp, &cp, 10); - if (*cp == '.') { - cp += 1; - ffsize = strtoul(cp, &cp, 10); - } - - idx += format_str_char(scope, mcd, leading_zero, - fsize, ffsize, *cp, - argc, argv, idx); - cp += 1; - - } - } - - return idx; -} - -static void do_display_numeric(unsigned int mcd, - struct strobe_cb_info*info, - vpiHandle item) -{ - int size; - s_vpi_value value; - - value.format = info->default_format; - vpi_get_value(item, &value); - - switch(info->default_format){ - case vpiDecStrVal: - size = vpi_get_dec_size(item); - my_mcd_printf(mcd, "%*s", size, value.value.str); - break; - - default: - my_mcd_printf(mcd, "%s", value.value.str); - } -} - -static void do_display(unsigned int mcd, struct strobe_cb_info*info) -{ - char*fmt; - s_vpi_value value; - unsigned int idx; - - for (idx = 0 ; idx < info->nitems ; idx += 1) { - vpiHandle item = info->items[idx]; - - switch (vpi_get(vpiType, item)) { - - case 0: - my_mcd_printf(mcd, " "); - break; - - case vpiConstant: - case vpiParameter: - if (vpi_get(vpiConstType, item) == vpiStringConst) { - value.format = vpiStringVal; - vpi_get_value(item, &value); - fmt = strdup(value.value.str); - idx += format_str(info->scope, mcd, fmt, - info->nitems-idx-1, - info->items+idx+1); - free(fmt); - } else { - do_display_numeric(mcd, info, item); - } - break; - - case vpiNet: - case vpiReg: - case vpiIntegerVar: - case vpiMemoryWord: - case vpiPartSelect: - do_display_numeric(mcd, info, item); - break; - - case vpiTimeVar: - value.format = vpiTimeVal; - vpi_get_value(item, &value); - my_mcd_printf(mcd, "%20u", value.value.time->low); - break; - - case vpiRealVar: - value.format = vpiRealVal; - vpi_get_value(item, &value); - my_mcd_printf(mcd, "%f", value.value.real); - break; - - case vpiSysFuncCall: { - char*tmp = vpi_get_str(vpiName, item); - vpiHandle scope = vpi_handle(vpiScope, item); - - /* This is wrong, but will be replaced with the - * the string formatting below soon. */ - if (strcmp(tmp,"$time") == 0 || - strcmp(tmp,"$stime") == 0 || - strcmp(tmp,"$simtime") == 0) { - value.format = vpiTimeVal; - vpi_get_value(item, &value); - my_mcd_printf(mcd, "%20u", value.value.time->low); - } else if (strcmp(tmp,"$realtime") == 0) { - int time_units = vpi_get(vpiTimeUnit, scope); - int time_prec = vpi_get(vpiTimePrecision, 0); - int use_prec = time_units - time_prec; - if (use_prec < 0) - use_prec = 0; - - value.format = vpiRealVal; - vpi_get_value(item, &value); - my_mcd_printf(mcd, "%0.*f", use_prec, - value.value.real); - } else { - my_mcd_printf(mcd, "<%s>", tmp); - } - break; - } - - default: - my_mcd_printf(mcd, "?"); - break; - } - } -} - static int get_default_format(char *name) { int default_format; @@ -919,146 +151,6 @@ static int get_default_format(char *name) return default_format; } -/* - * The $monitor system task works by managing these static variables, - * and the cbValueChange callbacks associated with registers and - * nets. Note that it is proper to keep the state in static variables - * because there can only be one monitor at a time pending (even - * though that monitor may be watching many variables). - */ - -static struct strobe_cb_info monitor_info = { 0, 0, 0, 0, 0 }; -static vpiHandle *monitor_callbacks = 0; -static int monitor_scheduled = 0; -static int monitor_enabled = 1; - -static PLI_INT32 monitor_cb_2(p_cb_data cb) -{ - do_display(1, &monitor_info); - vpi_printf("\n"); - monitor_scheduled = 0; - return 0; -} - -/* - * The monitor_cb_1 callback is called when an event occurs somewhere - * in the simulation. All this function does is schedule the actual - * display to occur in a ReadOnlySync callback. The monitor_scheduled - * flag is used to allow only one monitor strobe to be scheduled. - */ -static PLI_INT32 monitor_cb_1(p_cb_data cause) -{ - struct t_cb_data cb; - struct t_vpi_time time; - - if (monitor_enabled == 0) return 0; - if (monitor_scheduled) return 0; - - /* This this action caused the first trigger, then schedule - the monitor to happen at the end of the time slice and mark - it as scheduled. */ - monitor_scheduled += 1; - time.type = vpiSimTime; - time.low = 0; - time.high = 0; - - cb.reason = cbReadOnlySynch; - cb.cb_rtn = monitor_cb_2; - cb.time = &time; - cb.obj = 0; - cb.value = 0; - vpi_register_cb(&cb); - - return 0; -} - -static PLI_INT32 sys_monitor_calltf(PLI_BYTE8*name) -{ - unsigned idx; - struct t_cb_data cb; - struct t_vpi_time time; - - vpiHandle sys = vpi_handle(vpiSysTfCall, 0); - vpiHandle scope = vpi_handle(vpiScope, sys); - vpiHandle argv = vpi_iterate(vpiArgument, sys); - - /* If there was a previous $monitor, then remove the callbacks - related to it. */ - if (monitor_callbacks) { - for (idx = 0 ; idx < monitor_info.nitems ; idx += 1) - if (monitor_callbacks[idx]) - vpi_remove_cb(monitor_callbacks[idx]); - - free(monitor_callbacks); - monitor_callbacks = 0; - - free(monitor_info.items); - free(monitor_info.name); - monitor_info.items = 0; - monitor_info.nitems = 0; - monitor_info.name = 0; - } - - /* Make an array of handles from the argument list. */ - array_from_iterator(&monitor_info, argv); - monitor_info.name = strdup(name); - monitor_info.default_format = get_default_format(name); - monitor_info.scope = scope; - - /* Attach callbacks to all the parameters that might change. */ - monitor_callbacks = calloc(monitor_info.nitems, sizeof(vpiHandle)); - - time.type = vpiSuppressTime; - cb.reason = cbValueChange; - cb.cb_rtn = monitor_cb_1; - cb.time = &time; - cb.value = NULL; - for (idx = 0 ; idx < monitor_info.nitems ; idx += 1) { - - switch (vpi_get(vpiType, monitor_info.items[idx])) { - case vpiMemoryWord: - /* - * We only support constant selections. Make this - * better when we add a real compiletf routine. - */ - assert(vpi_get(vpiConstantSelect, monitor_info.items[idx])); - case vpiNet: - case vpiReg: - case vpiIntegerVar: - case vpiRealVar: - case vpiPartSelect: - /* Monitoring reg and net values involves setting - a callback for value changes. Pass the storage - pointer for the callback itself as user_data so - that the callback can refresh itself. */ - cb.user_data = (char*)(monitor_callbacks+idx); - cb.obj = monitor_info.items[idx]; - monitor_callbacks[idx] = vpi_register_cb(&cb); - break; - - } - } - - /* When the $monitor is called, it schedules a first display - for the end of the current time, like a $strobe. */ - monitor_cb_1(0); - - return 0; -} - -static PLI_INT32 sys_monitoron_calltf(PLI_BYTE8*name) -{ - monitor_enabled = 1; - monitor_cb_1(0); - return 0; -} - -static PLI_INT32 sys_monitoroff_calltf(PLI_BYTE8*name) -{ - monitor_enabled = 0; - return 0; -} - /* Build the format using the variables that control how the item will * be printed. This is used in error messages and directly by the e/f/g * format codes (minus the enclosing <>). The user needs to free the @@ -1899,8 +991,8 @@ static char *get_display(unsigned int *rtnsz, struct strobe_cb_info *info) break; default: - vpi_printf("WARNING: %s:%d: unknown argument type (%d) given to %s!\n", - info->filename, info->lineno, vpi_get(vpiType, item), + vpi_printf("WARNING: %s:%d: unknown argument type (%s) given to %s!\n", + info->filename, info->lineno, vpi_get_str(vpiType, item), info->name); result = ""; width = strlen(result); @@ -1915,34 +1007,88 @@ static char *get_display(unsigned int *rtnsz, struct strobe_cb_info *info) return rtn; } -/* - * This routine checks the file descriptor/MCD for the $fdisplay and - * $fwrite based tasks. - */ -static PLI_INT32 sys_file_compiletf(PLI_BYTE8*name) +static int sys_check_args(vpiHandle callh, vpiHandle argv, PLI_BYTE8*name, + int no_auto, int is_monitor) +{ + vpiHandle arg; + int ret = 0; + + /* If there are no arguments, just return. */ + if (argv == 0) return ret; + + for (arg = vpi_scan(argv); arg; arg = vpi_scan(argv)) { + if (no_auto && vpi_get(vpiAutomatic, arg)) { + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s argument \"%s\" is an automatic variable.\n", + name, vpi_get_str(vpiName, arg)); + ret = 1; + } + + switch (vpi_get(vpiType, arg)) { + case vpiMemoryWord: + case vpiPartSelect: + if (is_monitor && vpi_get(vpiConstantSelect, arg) == 0) { + vpi_printf("SORRY: %s:%d: ", + vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s must have a constant %s select.\n", + name, vpi_get_str(vpiType, arg)); + ret = 1; + } + + case vpiConstant: + case vpiParameter: + case vpiNet: + case vpiReg: + case vpiIntegerVar: + case vpiTimeVar: + case vpiRealVar: + case vpiSysFuncCall: + break; + + default: + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s does not support argument type (%s).\n", name, + vpi_get_str(vpiType, arg)); + ret = 1; + break; + } + } + + return ret; +} + +/* Check the $display, $write, $fdisplay and $fwrite based tasks. */ +static PLI_INT32 sys_display_compiletf(PLI_BYTE8*name) { vpiHandle callh, argv; callh = vpi_handle(vpiSysTfCall, 0); argv = vpi_iterate(vpiArgument, callh); - /* Check that there is a fd/mcd and that it is numeric. */ - if (argv == 0) { - vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), - (int)vpi_get(vpiLineNo, callh)); - vpi_printf("%s requires at least a file descriptor/MCD.\n", name); - vpi_control(vpiFinish, 1); - return 0; + if(name[1] == 'f') { + /* Check that there is a fd/mcd and that it is numeric. */ + if (argv == 0) { + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s requires at least a file descriptor/MCD.\n", + name); + vpi_control(vpiFinish, 1); + return 0; + } + + if (! is_numeric_obj(vpi_scan(argv))) { + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s's file descriptor/MCD must be numeric.\n", + name); + vpi_control(vpiFinish, 1); + } } - if (! is_numeric_obj(vpi_scan(argv))) { - vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), - (int)vpi_get(vpiLineNo, callh)); - vpi_printf("%s's file descriptor/MCD must be numeric.\n", name); - vpi_control(vpiFinish, 1); - } - - vpi_free_object(argv); + if (sys_check_args(callh, argv, name, 0, 0)) vpi_control(vpiFinish, 1); return 0; } @@ -1995,7 +1141,7 @@ static PLI_INT32 sys_display_calltf(PLI_BYTE8 *name) result = get_display(&size, &info); while (location < size) { if (result[location] == '\0') { - my_mcd_printf(fd_mcd, "\0"); + my_mcd_printf(fd_mcd, "%c", '\0'); location += 1; } else { my_mcd_printf(fd_mcd, "%s", &result[location]); @@ -2045,43 +1191,36 @@ static PLI_INT32 strobe_cb(p_cb_data cb) return 0; } -/* Used by $fstrobe. */ -static PLI_INT32 sys_file_no_aa_compiletf(PLI_BYTE8 *name) +/* Check both the $strobe and $fstrobe based tasks. */ +static PLI_INT32 sys_strobe_compiletf(PLI_BYTE8 *name) { vpiHandle callh, argv, arg; callh = vpi_handle(vpiSysTfCall, 0); argv = vpi_iterate(vpiArgument, callh); - /* Check that there is a fd/mcd and that it is numeric. */ - if (argv == 0) { - vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), - (int)vpi_get(vpiLineNo, callh)); - vpi_printf("%s requires at least a file descriptor/MCD.\n", name); - vpi_control(vpiFinish, 1); - return 0; - } + if(name[1] == 'f') { + /* Check that there is a fd/mcd and that it is numeric. */ + if (argv == 0) { + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s requires at least a file descriptor/MCD.\n", + name); + vpi_control(vpiFinish, 1); + return 0; + } - arg = vpi_scan(argv); - if (! is_numeric_obj(arg)) { - vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), - (int)vpi_get(vpiLineNo, callh)); - vpi_printf("%s's file descriptor/MCD must be numeric.\n", name); - vpi_control(vpiFinish, 1); - } - - /* Verify that $fstrobe is not passed any automatic variables. */ - for ( ; arg ; arg = vpi_scan(argv)) { - if (vpi_get(vpiAutomatic, arg)) { - vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), - (int)vpi_get(vpiLineNo, callh)); - vpi_printf("%s arguments may not be automatically " - "allocated variables.\n", name); - vpi_control(vpiFinish, 1); - vpi_free_object(argv); - return 0; + arg = vpi_scan(argv); + if (! is_numeric_obj(arg)) { + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s's file descriptor/MCD must be numeric.\n", + name); + vpi_control(vpiFinish, 1); } } + + if (sys_check_args(callh, argv, name, 1, 0)) vpi_control(vpiFinish, 1); return 0; } @@ -2146,6 +1285,175 @@ static PLI_INT32 sys_strobe_calltf(PLI_BYTE8*name) return 0; } +/* + * The $monitor system task works by managing these static variables, + * and the cbValueChange callbacks associated with registers and + * nets. Note that it is proper to keep the state in static variables + * because there can only be one monitor at a time pending (even + * though that monitor may be watching many variables). + */ + +static struct strobe_cb_info monitor_info = { 0, 0, 0, 0, 0, 0, 0, 0 }; +static vpiHandle *monitor_callbacks = 0; +static int monitor_scheduled = 0; +static int monitor_enabled = 1; + +static PLI_INT32 monitor_cb_2(p_cb_data cb) +{ + char* result; + unsigned int size, location=0; + + /* Because %u and %z may put embedded NULL characters into the + * returned string strlen() may not match the real size! */ + result = get_display(&size, &monitor_info); + while (location < size) { + if (result[location] == '\0') { + my_mcd_printf(monitor_info.fd_mcd, "%c", '\0'); + location += 1; + } else { + my_mcd_printf(monitor_info.fd_mcd, "%s", &result[location]); + location += strlen(&result[location]); + } + } + my_mcd_printf(monitor_info.fd_mcd, "\n"); + monitor_scheduled = 0; + free(result); + return 0; +} + +/* + * The monitor_cb_1 callback is called when an event occurs somewhere + * in the simulation. All this function does is schedule the actual + * display to occur in a ReadOnlySync callback. The monitor_scheduled + * flag is used to allow only one monitor strobe to be scheduled. + */ +static PLI_INT32 monitor_cb_1(p_cb_data cause) +{ + struct t_cb_data cb; + struct t_vpi_time time; + + if (monitor_enabled == 0) return 0; + if (monitor_scheduled) return 0; + + /* This this action caused the first trigger, then schedule + the monitor to happen at the end of the time slice and mark + it as scheduled. */ + monitor_scheduled += 1; + time.type = vpiSimTime; + time.low = 0; + time.high = 0; + + cb.reason = cbReadOnlySynch; + cb.cb_rtn = monitor_cb_2; + cb.time = &time; + cb.obj = 0; + cb.value = 0; + vpi_register_cb(&cb); + + return 0; +} + +static PLI_INT32 sys_monitor_compiletf(PLI_BYTE8 *name) +{ + vpiHandle callh = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv = vpi_iterate(vpiArgument, callh); + + if (sys_check_args(callh, argv, name, 1, 1)) vpi_control(vpiFinish, 1); + return 0; +} + +static PLI_INT32 sys_monitor_calltf(PLI_BYTE8*name) +{ + vpiHandle callh, argv, scope; + unsigned idx; + struct t_cb_data cb; + struct t_vpi_time time; + + callh = vpi_handle(vpiSysTfCall, 0); + argv = vpi_iterate(vpiArgument, callh); + + /* If there was a previous $monitor, then remove the callbacks + related to it. */ + if (monitor_callbacks) { + for (idx = 0 ; idx < monitor_info.nitems ; idx += 1) + if (monitor_callbacks[idx]) + vpi_remove_cb(monitor_callbacks[idx]); + + free(monitor_callbacks); + monitor_callbacks = 0; + + free(monitor_info.filename); + free(monitor_info.items); + monitor_info.items = 0; + monitor_info.nitems = 0; + monitor_info.name = 0; + } + + scope = vpi_handle(vpiScope, callh); + assert(scope); + /* Make an array of handles from the argument list. */ + array_from_iterator(&monitor_info, argv); + monitor_info.name = name; + monitor_info.filename = strdup(vpi_get_str(vpiFile, callh)); + monitor_info.lineno = (int)vpi_get(vpiLineNo, callh); + monitor_info.default_format = get_default_format(name); + monitor_info.scope = scope; + monitor_info.fd_mcd = 1; + + /* Attach callbacks to all the parameters that might change. */ + monitor_callbacks = calloc(monitor_info.nitems, sizeof(vpiHandle)); + + time.type = vpiSuppressTime; + cb.reason = cbValueChange; + cb.cb_rtn = monitor_cb_1; + cb.time = &time; + cb.value = NULL; + for (idx = 0 ; idx < monitor_info.nitems ; idx += 1) { + + switch (vpi_get(vpiType, monitor_info.items[idx])) { + case vpiMemoryWord: + /* + * We only support constant selections. Make this + * better when we add a real compiletf routine. + */ + assert(vpi_get(vpiConstantSelect, monitor_info.items[idx])); + case vpiNet: + case vpiReg: + case vpiIntegerVar: + case vpiRealVar: + case vpiPartSelect: + /* Monitoring reg and net values involves setting + a callback for value changes. Pass the storage + pointer for the callback itself as user_data so + that the callback can refresh itself. */ + cb.user_data = (char*)(monitor_callbacks+idx); + cb.obj = monitor_info.items[idx]; + monitor_callbacks[idx] = vpi_register_cb(&cb); + break; + + } + } + + /* When the $monitor is called, it schedules a first display + for the end of the current time, like a $strobe. */ + monitor_cb_1(0); + + return 0; +} + +static PLI_INT32 sys_monitoron_calltf(PLI_BYTE8*name) +{ + monitor_enabled = 1; + monitor_cb_1(0); + return 0; +} + +static PLI_INT32 sys_monitoroff_calltf(PLI_BYTE8*name) +{ + monitor_enabled = 0; + return 0; +} + static PLI_INT32 sys_swrite_compiletf(PLI_BYTE8 *name) { vpiHandle callh = vpi_handle(vpiSysTfCall, 0); @@ -2171,7 +1479,7 @@ static PLI_INT32 sys_swrite_compiletf(PLI_BYTE8 *name) return 0; } - vpi_free_object(argv); + if (sys_check_args(callh, argv, name, 0, 0)) vpi_control(vpiFinish, 1); return 0; } @@ -2258,7 +1566,7 @@ static PLI_INT32 sys_sformat_compiletf(PLI_BYTE8 *name) return 0; } - vpi_free_object(argv); + if (sys_check_args(callh, argv, name, 0, 0)) vpi_control(vpiFinish, 1); return 0; } @@ -2440,29 +1748,6 @@ static PLI_INT32 sys_printtimescale_calltf(PLI_BYTE8*xx) return 0; } -/* Used by $strobe and $monitor. */ -static PLI_INT32 sys_no_aa_compiletf(PLI_BYTE8 *name) -{ - vpiHandle callh = vpi_handle(vpiSysTfCall, 0); - vpiHandle argv = vpi_iterate(vpiArgument, callh); - vpiHandle arg; - /* If there are no arguments, just return. */ - if (argv == 0) return 0; - - for (arg = vpi_scan(argv) ; arg ; arg = vpi_scan(argv)) { - if (vpi_get(vpiAutomatic, arg)) { - vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), - (int)vpi_get(vpiLineNo, callh)); - vpi_printf("%s arguments may not be automatically " - "allocated variables.\n", name); - vpi_control(vpiFinish, 1); - vpi_free_object(argv); - return 0; - } - } - return 0; -} - void sys_display_register() { s_cb_data cb_data; @@ -2472,7 +1757,7 @@ void sys_display_register() tf_data.type = vpiSysTask; tf_data.tfname = "$display"; tf_data.calltf = sys_display_calltf; - tf_data.compiletf = 0; + tf_data.compiletf = sys_display_compiletf; tf_data.sizetf = 0; tf_data.user_data = "$display"; vpi_register_systf(&tf_data); @@ -2480,7 +1765,7 @@ void sys_display_register() tf_data.type = vpiSysTask; tf_data.tfname = "$displayh"; tf_data.calltf = sys_display_calltf; - tf_data.compiletf = 0; + tf_data.compiletf = sys_display_compiletf; tf_data.sizetf = 0; tf_data.user_data = "$displayh"; vpi_register_systf(&tf_data); @@ -2488,7 +1773,7 @@ void sys_display_register() tf_data.type = vpiSysTask; tf_data.tfname = "$displayo"; tf_data.calltf = sys_display_calltf; - tf_data.compiletf = 0; + tf_data.compiletf = sys_display_compiletf; tf_data.sizetf = 0; tf_data.user_data = "$displayo"; vpi_register_systf(&tf_data); @@ -2496,7 +1781,7 @@ void sys_display_register() tf_data.type = vpiSysTask; tf_data.tfname = "$displayb"; tf_data.calltf = sys_display_calltf; - tf_data.compiletf = 0; + tf_data.compiletf = sys_display_compiletf; tf_data.sizetf = 0; tf_data.user_data = "$displayb"; vpi_register_systf(&tf_data); @@ -2505,7 +1790,7 @@ void sys_display_register() tf_data.type = vpiSysTask; tf_data.tfname = "$write"; tf_data.calltf = sys_display_calltf; - tf_data.compiletf = 0; + tf_data.compiletf = sys_display_compiletf; tf_data.sizetf = 0; tf_data.user_data = "$write"; vpi_register_systf(&tf_data); @@ -2513,7 +1798,7 @@ void sys_display_register() tf_data.type = vpiSysTask; tf_data.tfname = "$writeh"; tf_data.calltf = sys_display_calltf; - tf_data.compiletf = 0; + tf_data.compiletf = sys_display_compiletf; tf_data.sizetf = 0; tf_data.user_data = "$writeh"; vpi_register_systf(&tf_data); @@ -2521,7 +1806,7 @@ void sys_display_register() tf_data.type = vpiSysTask; tf_data.tfname = "$writeo"; tf_data.calltf = sys_display_calltf; - tf_data.compiletf = 0; + tf_data.compiletf = sys_display_compiletf; tf_data.sizetf = 0; tf_data.user_data = "$writeo"; vpi_register_systf(&tf_data); @@ -2529,7 +1814,7 @@ void sys_display_register() tf_data.type = vpiSysTask; tf_data.tfname = "$writeb"; tf_data.calltf = sys_display_calltf; - tf_data.compiletf = 0; + tf_data.compiletf = sys_display_compiletf; tf_data.sizetf = 0; tf_data.user_data = "$writeb"; vpi_register_systf(&tf_data); @@ -2538,7 +1823,7 @@ void sys_display_register() tf_data.type = vpiSysTask; tf_data.tfname = "$strobe"; tf_data.calltf = sys_strobe_calltf; - tf_data.compiletf = sys_no_aa_compiletf; + tf_data.compiletf = sys_strobe_compiletf; tf_data.sizetf = 0; tf_data.user_data = "$strobe"; vpi_register_systf(&tf_data); @@ -2546,7 +1831,7 @@ void sys_display_register() tf_data.type = vpiSysTask; tf_data.tfname = "$strobeh"; tf_data.calltf = sys_strobe_calltf; - tf_data.compiletf = sys_no_aa_compiletf; + tf_data.compiletf = sys_strobe_compiletf; tf_data.sizetf = 0; tf_data.user_data = "$strobeh"; vpi_register_systf(&tf_data); @@ -2554,7 +1839,7 @@ void sys_display_register() tf_data.type = vpiSysTask; tf_data.tfname = "$strobeo"; tf_data.calltf = sys_strobe_calltf; - tf_data.compiletf = sys_no_aa_compiletf; + tf_data.compiletf = sys_strobe_compiletf; tf_data.sizetf = 0; tf_data.user_data = "$strobeo"; vpi_register_systf(&tf_data); @@ -2562,7 +1847,7 @@ void sys_display_register() tf_data.type = vpiSysTask; tf_data.tfname = "$strobeb"; tf_data.calltf = sys_strobe_calltf; - tf_data.compiletf = sys_no_aa_compiletf; + tf_data.compiletf = sys_strobe_compiletf; tf_data.sizetf = 0; tf_data.user_data = "$strobeb"; vpi_register_systf(&tf_data); @@ -2571,7 +1856,7 @@ void sys_display_register() tf_data.type = vpiSysTask; tf_data.tfname = "$fstrobe"; tf_data.calltf = sys_strobe_calltf; - tf_data.compiletf = sys_file_no_aa_compiletf; + tf_data.compiletf = sys_strobe_compiletf; tf_data.sizetf = 0; tf_data.user_data = "$fstrobe"; vpi_register_systf(&tf_data); @@ -2579,7 +1864,7 @@ void sys_display_register() tf_data.type = vpiSysTask; tf_data.tfname = "$fstrobeh"; tf_data.calltf = sys_strobe_calltf; - tf_data.compiletf = sys_file_no_aa_compiletf; + tf_data.compiletf = sys_strobe_compiletf; tf_data.sizetf = 0; tf_data.user_data = "$fstrobeh"; vpi_register_systf(&tf_data); @@ -2587,7 +1872,7 @@ void sys_display_register() tf_data.type = vpiSysTask; tf_data.tfname = "$fstrobeo"; tf_data.calltf = sys_strobe_calltf; - tf_data.compiletf = sys_file_no_aa_compiletf; + tf_data.compiletf = sys_strobe_compiletf; tf_data.sizetf = 0; tf_data.user_data = "$fstrobeo"; vpi_register_systf(&tf_data); @@ -2595,7 +1880,7 @@ void sys_display_register() tf_data.type = vpiSysTask; tf_data.tfname = "$fstrobeb"; tf_data.calltf = sys_strobe_calltf; - tf_data.compiletf = sys_file_no_aa_compiletf; + tf_data.compiletf = sys_strobe_compiletf; tf_data.sizetf = 0; tf_data.user_data = "$fstrobeb"; vpi_register_systf(&tf_data); @@ -2604,7 +1889,7 @@ void sys_display_register() tf_data.type = vpiSysTask; tf_data.tfname = "$monitor"; tf_data.calltf = sys_monitor_calltf; - tf_data.compiletf = sys_no_aa_compiletf; + tf_data.compiletf = sys_monitor_compiletf; tf_data.sizetf = 0; tf_data.user_data = "$monitor"; vpi_register_systf(&tf_data); @@ -2612,7 +1897,7 @@ void sys_display_register() tf_data.type = vpiSysTask; tf_data.tfname = "$monitorh"; tf_data.calltf = sys_monitor_calltf; - tf_data.compiletf = sys_no_aa_compiletf; + tf_data.compiletf = sys_monitor_compiletf; tf_data.sizetf = 0; tf_data.user_data = "$monitorh"; vpi_register_systf(&tf_data); @@ -2620,7 +1905,7 @@ void sys_display_register() tf_data.type = vpiSysTask; tf_data.tfname = "$monitoro"; tf_data.calltf = sys_monitor_calltf; - tf_data.compiletf = sys_no_aa_compiletf; + tf_data.compiletf = sys_monitor_compiletf; tf_data.sizetf = 0; tf_data.user_data = "$monitoro"; vpi_register_systf(&tf_data); @@ -2628,7 +1913,7 @@ void sys_display_register() tf_data.type = vpiSysTask; tf_data.tfname = "$monitorb"; tf_data.calltf = sys_monitor_calltf; - tf_data.compiletf = sys_no_aa_compiletf; + tf_data.compiletf = sys_monitor_compiletf; tf_data.sizetf = 0; tf_data.user_data = "$monitorb"; vpi_register_systf(&tf_data); @@ -2653,7 +1938,7 @@ void sys_display_register() tf_data.type = vpiSysTask; tf_data.tfname = "$fdisplay"; tf_data.calltf = sys_display_calltf; - tf_data.compiletf = sys_file_compiletf; + tf_data.compiletf = sys_display_compiletf; tf_data.sizetf = 0; tf_data.user_data = "$fdisplay"; vpi_register_systf(&tf_data); @@ -2661,7 +1946,7 @@ void sys_display_register() tf_data.type = vpiSysTask; tf_data.tfname = "$fdisplayh"; tf_data.calltf = sys_display_calltf; - tf_data.compiletf = sys_file_compiletf; + tf_data.compiletf = sys_display_compiletf; tf_data.sizetf = 0; tf_data.user_data = "$fdisplayh"; vpi_register_systf(&tf_data); @@ -2669,7 +1954,7 @@ void sys_display_register() tf_data.type = vpiSysTask; tf_data.tfname = "$fdisplayo"; tf_data.calltf = sys_display_calltf; - tf_data.compiletf = sys_file_compiletf; + tf_data.compiletf = sys_display_compiletf; tf_data.sizetf = 0; tf_data.user_data = "$fdisplayo"; vpi_register_systf(&tf_data); @@ -2677,7 +1962,7 @@ void sys_display_register() tf_data.type = vpiSysTask; tf_data.tfname = "$fdisplayb"; tf_data.calltf = sys_display_calltf; - tf_data.compiletf = sys_file_compiletf; + tf_data.compiletf = sys_display_compiletf; tf_data.sizetf = 0; tf_data.user_data = "$fdisplayb"; vpi_register_systf(&tf_data); @@ -2686,7 +1971,7 @@ void sys_display_register() tf_data.type = vpiSysTask; tf_data.tfname = "$fwrite"; tf_data.calltf = sys_display_calltf; - tf_data.compiletf = sys_file_compiletf; + tf_data.compiletf = sys_display_compiletf; tf_data.sizetf = 0; tf_data.user_data = "$fwrite"; vpi_register_systf(&tf_data); @@ -2694,7 +1979,7 @@ void sys_display_register() tf_data.type = vpiSysTask; tf_data.tfname = "$fwriteh"; tf_data.calltf = sys_display_calltf; - tf_data.compiletf = sys_file_compiletf; + tf_data.compiletf = sys_display_compiletf; tf_data.sizetf = 0; tf_data.user_data = "$fwriteh"; vpi_register_systf(&tf_data); @@ -2702,7 +1987,7 @@ void sys_display_register() tf_data.type = vpiSysTask; tf_data.tfname = "$fwriteo"; tf_data.calltf = sys_display_calltf; - tf_data.compiletf = sys_file_compiletf; + tf_data.compiletf = sys_display_compiletf; tf_data.sizetf = 0; tf_data.user_data = "$fwriteo"; vpi_register_systf(&tf_data); @@ -2710,7 +1995,7 @@ void sys_display_register() tf_data.type = vpiSysTask; tf_data.tfname = "$fwriteb"; tf_data.calltf = sys_display_calltf; - tf_data.compiletf = sys_file_compiletf; + tf_data.compiletf = sys_display_compiletf; tf_data.sizetf = 0; tf_data.user_data = "$fwriteb"; vpi_register_systf(&tf_data); diff --git a/vvp/array.cc b/vvp/array.cc index 875a0ed1c..46fdcf456 100644 --- a/vvp/array.cc +++ b/vvp/array.cc @@ -640,10 +640,13 @@ static int vpi_array_vthr_A_get(int code, vpiHandle ref) case vpiAutomatic: return (int) parent->scope->is_automatic; - // For now &A<> is only a constant select. This will need - // to be changed when it supports variable selection. + // If address_handle is not zero we definitely have a + // variable. If the wid is not zero we have a calculation + // from thread space which probably includes a variable. + // This assumes that the compiler is squashing all the + // constant expressions down to a single value. case vpiConstantSelect: - return 1; + return obj->address_handle == 0 && obj->wid == 0; default: return 0; diff --git a/vvp/vpi_priv.cc b/vvp/vpi_priv.cc index 0ec53b1b9..f42dfbcde 100644 --- a/vvp/vpi_priv.cc +++ b/vvp/vpi_priv.cc @@ -228,6 +228,10 @@ static const char* vpi_type_values(PLI_INT32 code) return "vpiRealVar"; case vpiReg: return "vpiReg"; + case vpiSysFuncCall: + return "vpiSysFuncCall"; + case vpiSysTaskCall: + return "vpiSysTaskCall"; case vpiTask: return "vpiTask"; case vpiTimeVar: diff --git a/vvp/vpi_signal.cc b/vvp/vpi_signal.cc index a46303228..b30136f0a 100644 --- a/vvp/vpi_signal.cc +++ b/vvp/vpi_signal.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2008 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2009 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -972,8 +972,9 @@ static int PV_get(int code, vpiHandle ref) case vpiSize: return rfp->width; + /* This is like the &A<> in array.cc. */ case vpiConstantSelect: - return rfp->twid == 0; + return rfp->sbase == 0 && rfp->twid == 0; case vpiLeftRange: rval += rfp->width;