From 80e596b212c55dbebc4dec75f1034594743ebada Mon Sep 17 00:00:00 2001 From: Cary R Date: Tue, 6 Jan 2009 10:41:39 -0800 Subject: [PATCH] Add leading 0 support to $swrite/$sformat and $display uses this code. This patch does a number of things. It adds file and line number information to the strobe_cb_info structure. This allows the $swrite and $sformat calls to reference their location in warning/error messages. Their compiletf and calltf routines also display file and line number information in messages. The $display routine was converted to use the string formatting routine. This can be reverted by defining USE_OLD_DISPLAY. The old code will be removed once there has been more testing. A number of bugs were fixed that were discovered with the $display code. The output of some conversions, variables and system functions were changed to match the original display code or to better match expectation. Leading zero support was added to the %b/%b, %o/%O, %h/%H, %x/%X, %c/%C and %d/%D. The floating point conversions already supported adding a leading zero. This is the start of converting all the various display tasks to use the string formatting code and a cleanup/update of the sys_display.c file in general. --- vpi/sys_display.c | 493 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 347 insertions(+), 146 deletions(-) diff --git a/vpi/sys_display.c b/vpi/sys_display.c index 59f70ed29..b4c68aae1 100644 --- a/vpi/sys_display.c +++ b/vpi/sys_display.c @@ -53,6 +53,8 @@ struct timeformat_info_s timeformat_info = { 0, 0, 0, 20 }; struct strobe_cb_info { char*name; + char*filename; + int lineno; int default_format; vpiHandle scope; vpiHandle*items; @@ -914,6 +916,7 @@ static int get_default_format(char *name) return default_format; } +#ifdef USE_OLD_DISPLAY static PLI_INT32 sys_display_calltf(PLI_BYTE8*name) { struct strobe_cb_info*info; @@ -940,6 +943,7 @@ static PLI_INT32 sys_display_calltf(PLI_BYTE8*name) return 0; } +#endif /* * The strobe implementation takes the parameter handles that are @@ -1257,6 +1261,8 @@ static char * format_as_string(int ljust, int plus, int ld_zero, int width, char buf[256]; unsigned int size = 0; + /* Do not remove/change the "<" without also changing the e/f/g format + * code below! */ buf[size++] = '<'; buf[size++] = '%'; if (ljust == 1) buf[size++] = '-'; @@ -1267,7 +1273,7 @@ static char * format_as_string(int ljust, int plus, int ld_zero, int width, if (prec != -1) size += sprintf(&buf[size], ".%d", prec); buf[size++] = fmt; - /* Do not change this without also changing the e/f/g format code below! */ + /* The same goes here ">"! */ buf[size++] = '>'; buf[size] = '\0'; return strdup(buf); @@ -1301,16 +1307,20 @@ static void get_time(char *rtn, const char *value, int prec, /* We have digits to the left of the decimal point. */ if (head > 0) { strncpy(rtn, value, head); - strcat(rtn, "."); - strncat(rtn, &value[head], prec); - tail = prec + shift; - while (tail > 0) { - strcat(rtn, "0"); - tail -= 1; + *(rtn+head) = '\0'; + if (prec > 0) { + strcat(rtn, "."); + strncat(rtn, &value[head], prec); + tail = prec + shift; + while (tail > 0) { + strcat(rtn, "0"); + tail -= 1; + } } /* All digits are to the right of the decimal point. */ } else { - strcpy(rtn, "0."); + strcpy(rtn, "0"); + if (prec > 0) strcat(rtn, "."); /* Add leading zeros as needed. */ head = -shift - 1; if (head > prec) head = prec; @@ -1320,12 +1330,14 @@ static void get_time(char *rtn, const char *value, int prec, } /* Add digits from the value if they fit. */ tail = prec + shift + 1; - strncat(rtn, value, tail); - /* Add trailing zeros to fill out the precision. */ - tail = prec + shift + 1 - strlen(value); - while (tail > 0) { - strcat(rtn, "0"); - tail -= 1; + if (tail > 0) { + strncat(rtn, value, tail); + /* Add trailing zeros to fill out the precision. */ + tail = prec + shift + 1 - strlen(value); + while (tail > 0) { + strcat(rtn, "0"); + tail -= 1; + } } } } @@ -1366,7 +1378,8 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus, case '%': if (ljust != 0 || plus != 0 || ld_zero != 0 || width != -1 || prec != -1) { - vpi_printf("WARNING: invalid format %s%s.\n", info->name, fmtb); + vpi_printf("WARNING: %s:%d: invalid format %s%s.\n", + info->filename, info->lineno, info->name, fmtb); } strcpy(result, "%"); size = strlen(result) + 1; @@ -1382,10 +1395,12 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus, case 'X': *idx += 1; if (plus != 0 || prec != -1) { - vpi_printf("WARNING: invalid format %s%s.\n", info->name, fmtb); + vpi_printf("WARNING: %s:%d: invalid format %s%s.\n", + info->filename, info->lineno, info->name, fmtb); } if (*idx >= info->nitems) { - vpi_printf("WARNING: missing argument for %s%s.\n", info->name, fmtb); + vpi_printf("WARNING: %s:%d: missing argument for %s%s.\n", + info->filename, info->lineno, info->name, fmtb); } else { switch (fmt) { case 'b': @@ -1405,24 +1420,37 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus, } vpi_get_value(info->items[*idx], &value); if (value.format == vpiSuppressVal) { - vpi_printf("WARNING: incompatible value for %s%s.\n", info->name, - fmtb); + vpi_printf("WARNING: %s:%d: incompatible value for %s%s.\n", + info->filename, info->lineno, info->name, fmtb); } else { - char *cp; + unsigned swidth = strlen(value.value.str), free_flag = 0;; + char *cp = value.value.str; + + if (ld_zero == 1) { + /* Strip the leading zeros if a width is not given. */ + if (width == -1) while (*cp == '0') cp++; + /* Pad with leading zeros. */ + else if (ljust == 0 && (signed)swidth < width) { + unsigned pad = (unsigned)width - swidth; + cp = malloc((width+1)*sizeof(char)); + memset(cp, '0', pad); + strcpy(cp+pad, value.value.str); + free_flag = 1; + /* For a left aligned value also strip the leading zeros. */ + } else if (ljust != 0) while (*cp == '0') cp++; + } /* If a width was not given, use a width of zero. */ if (width == -1) width = 0; - /* Strip the leading zeros. */ - cp = value.value.str; - if (ld_zero == 1) { - while (*cp == '0') cp++; - } + /* If the default buffer is too small, make it big enough. */ size = strlen(cp) + 1; + if ((signed)size < (width+1)) size = width+1; if (size > ini_size) result = realloc(result, size*sizeof(char)); if (ljust == 0) sprintf(result, "%*s", width, cp); else sprintf(result, "%-*s", width, cp); + if (free_flag) free(cp); size = strlen(result) + 1; } } @@ -1432,23 +1460,37 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus, case 'C': *idx += 1; if (plus != 0 || prec != -1) { - vpi_printf("WARNING: invalid format %s%s.\n", info->name, fmtb); + vpi_printf("WARNING: %s:%d: invalid format %s%s.\n", + info->filename, info->lineno, info->name, fmtb); } if (*idx >= info->nitems) { - vpi_printf("WARNING: missing argument for %s%s.\n", info->name, fmtb); + vpi_printf("WARNING: %s:%d: missing argument for %s%s.\n", + info->filename, info->lineno, info->name, fmtb); } else { value.format = vpiStringVal; vpi_get_value(info->items[*idx], &value); if (value.format == vpiSuppressVal) { - vpi_printf("WARNING: incompatible value for %s%s.\n", info->name, - fmtb); + vpi_printf("WARNING: %s:%d: incompatible value for %s%s.\n", + info->filename, info->lineno, info->name, fmtb); } else { - /* If a width was not given, use a width of zero. */ - if (width == -1) width = 0; - if (ljust == 0) sprintf(result, "%*c", width, - value.value.str[strlen(value.value.str)-1]); - else sprintf(result, "%-*c", width, - value.value.str[strlen(value.value.str)-1]); + char ch = value.value.str[strlen(value.value.str)-1]; + + /* If the default buffer is too small, make it big enough. */ + size = width + 1; + if (size > ini_size) result = realloc(result, size*sizeof(char)); + + /* If the width is less than one then use a width of one. */ + if (width < 1) width = 1; + if (ljust == 0) { + if (width > 1) { + char *cp = malloc((width+1)*sizeof(char)); + memset(cp, (ld_zero == 1 ? '0': ' '), width-1); + cp[width-1] = ch; + cp[width] = '\0'; + sprintf(result, "%*s", width, cp); + free(cp); + } else sprintf(result, "%c", ch); + } else sprintf(result, "%-*c", width, ch); size = strlen(result) + 1; } } @@ -1458,33 +1500,58 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus, case 'D': *idx += 1; if (prec != -1) { - vpi_printf("WARNING: invalid format %s%s.\n", info->name, fmtb); + vpi_printf("WARNING: %s:%d: invalid format %s%s.\n", + info->filename, info->lineno, info->name, fmtb); } if (*idx >= info->nitems) { - vpi_printf("WARNING: missing argument for %s%s.\n", info->name, fmtb); + vpi_printf("WARNING: %s:%d: missing argument for %s%s.\n", + info->filename, info->lineno, info->name, fmtb); } else { value.format = vpiDecStrVal; vpi_get_value(info->items[*idx], &value); if (value.format == vpiSuppressVal) { - vpi_printf("WARNING: incompatible value for %s%s.\n", info->name, - fmtb); + vpi_printf("WARNING: %s:%d: incompatible value for %s%s.\n", + info->filename, info->lineno, info->name, fmtb); } else { - char *tbuf; + unsigned pad = 0; + unsigned swidth = strlen(value.value.str) + + (value.value.str[0] == '-' ? 0 : (unsigned)plus); + char *tbuf, *cpb, *cp = value.value.str; + + /* Allocate storage and calculate the pad if needed. */ + if (ljust == 0 && ld_zero == 1 && (signed)swidth < width) { + tbuf = malloc((width+1)*sizeof(char)); + pad = (unsigned)width - swidth; + } else { + tbuf = malloc((swidth+1)*sizeof(char)); + } + cpb = tbuf; + + /* Insert the sign if needed. */ + if (plus == 1 && *cp != '-') { + *cpb = '+'; + cpb += 1; + } else if (*cp == '-') { + *cpb = '-'; + cpb += 1; + cp += 1; + } + + /* Now add padding if it is needed and then add the value. */ + memset(cpb, '0', pad); + strcpy(cpb+pad, cp); /* If a width was not given, use the default, unless we have a * leading zero (width of zero). */ if (width == -1) { - width = (ld_zero == 1) ? 0: vpi_get_dec_size(info->items[*idx]); + width = (ld_zero == 1) ? 0 : vpi_get_dec_size(info->items[*idx]); } - size = strlen(value.value.str) + 1 + plus; - /* Insert a plus sign if needed. */ - tbuf = malloc(size*sizeof(char)); - if (plus == 1 && value.value.str[0] != '-') { - tbuf[0] = '+'; - strcpy(&tbuf[1], value.value.str); - } else strcpy(&tbuf[0], value.value.str); + /* If the default buffer is too small make it big enough. */ + size = strlen(tbuf) + 1; + if ((signed)size < (width+1)) size = width+1; if (size > ini_size) result = realloc(result, size*sizeof(char)); + if (ljust == 0) sprintf(result, "%*s", width, tbuf); else sprintf(result, "%-*s", width, tbuf); free(tbuf); @@ -1501,13 +1568,14 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus, case 'G': *idx += 1; if (*idx >= info->nitems) { - vpi_printf("WARNING: missing argument for %s%s.\n", info->name, fmtb); + vpi_printf("WARNING: %s:%d: missing argument for %s%s.\n", + info->filename, info->lineno, info->name, fmtb); } else { value.format = vpiRealVal; vpi_get_value(info->items[*idx], &value); if (value.format == vpiSuppressVal) { - vpi_printf("WARNING: incompatible value for %s%s.\n", info->name, - fmtb); + vpi_printf("WARNING: %s:%d: incompatible value for %s%s.\n", + info->filename, info->lineno, info->name, fmtb); } else { char *cp = fmtb; @@ -1517,6 +1585,16 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus, } while (*cp != '>') cp++; *cp = '\0'; + + /* If the default buffer is too small make it big enough. + * + * This size may not always be correct, but if the default + * size is big enough for any practical value then all we + * need to worry about is extra padding and this should work + * correctly for that case, but since this uses the standard + * sprintf() routine we don't know exactly what it will do. */ + size = width + 1; + if (size > ini_size) result = realloc(result, size*sizeof(char)); sprintf(result, fmtb+1, value.value.real); size = strlen(result) + 1; } @@ -1527,43 +1605,59 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus, * vpiCell and vpiLibrary need to be implemented first. */ case 'l': case 'L': - vpi_printf("WARNING: %%%c currently unsupported %s%s.\n", fmt, - info->name, fmtb); + vpi_printf("WARNING: %s:%d: %%%c currently unsupported %s%s.\n", + info->filename, info->lineno, fmt, info->name, fmtb); break; case 'm': case 'M': if (plus != 0 || prec != -1) { - vpi_printf("WARNING: invalid format %s%s.\n", info->name, fmtb); + vpi_printf("WARNING: %s:%d: invalid format %s%s.\n", + info->filename, info->lineno, info->name, fmtb); } /* If a width was not given, use a width of zero. */ if (width == -1) width = 0; - if (ljust == 0) sprintf(result, "%*s", width, - vpi_get_str(vpiFullName, info->scope)); - else sprintf(result, "%-*s", width, - vpi_get_str(vpiFullName, info->scope)); + + { + char *cp = vpi_get_str(vpiFullName, info->scope); + /* If the default buffer is too small, make it big enough. */ + size = strlen(cp) + 1; + if ((signed)size < (width+1)) size = width+1; + if (size > ini_size) result = realloc(result, size*sizeof(char)); + + if (ljust == 0) sprintf(result, "%*s", width, cp); + else sprintf(result, "%-*s", width, cp); + } size = strlen(result) + 1; break; case 's': case 'S': + /* Strings are not numeric and are not zero filled, so %08s => %8s. */ *idx += 1; if (plus != 0 || prec != -1) { - vpi_printf("WARNING: invalid format %s%s.\n", info->name, fmtb); + vpi_printf("WARNING: %s:%d: invalid format %s%s.\n", + info->filename, info->lineno, info->name, fmtb); } if (*idx >= info->nitems) { - vpi_printf("WARNING: missing argument for %s%s.\n", info->name, fmtb); + vpi_printf("WARNING: %s:%d: missing argument for %s%s.\n", + info->filename, info->lineno, info->name, fmtb); } else { value.format = vpiStringVal; vpi_get_value(info->items[*idx], &value); if (value.format == vpiSuppressVal) { - vpi_printf("WARNING: incompatible value for %s%s.\n", info->name, - fmtb); + vpi_printf("WARNING: %s:%d: incompatible value for %s%s.\n", + info->filename, info->lineno, info->name, fmtb); } else { - /* If a width was not given, use a width of zero. */ - if (width == -1) width = 0; + if (width == -1) { + /* If all we have is a leading zero then we want a zero width. */ + if (ld_zero == 1) width = 0; + /* Otherwise if a width was not given, use the value width. */ + else width = (vpi_get(vpiSize, info->items[*idx])+7) / 8; + } /* If the default buffer is too small make it big enough. */ size = strlen(value.value.str) + 1; + if ((signed)size < (width+1)) size = width+1; if (size > ini_size) result = realloc(result, size*sizeof(char)); if (ljust == 0) sprintf(result, "%*s", width, value.value.str); else sprintf(result, "%-*s", width, value.value.str); @@ -1576,46 +1670,76 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus, case 'T': *idx += 1; if (plus != 0) { - vpi_printf("WARNING: invalid format %s%s.\n", info->name, fmtb); + vpi_printf("WARNING: %s:%d: invalid format %s%s.\n", + info->filename, info->lineno, info->name, fmtb); } if (*idx >= info->nitems) { - vpi_printf("WARNING: missing argument for %s%s.\n", info->name, fmtb); + vpi_printf("WARNING: %s:%d: missing argument for %s%s.\n", + info->filename, info->lineno, info->name, fmtb); } else { - char tbuf[256]; PLI_INT32 type; - PLI_INT32 time_units = vpi_get(vpiTimeUnit, info->scope); + /* Get the argument type and value. */ type = vpi_get(vpiType, info->items[*idx]); - if (width == -1) width = timeformat_info.width; - if (ld_zero == 1) width = 0; - if (prec == -1) prec = timeformat_info.prec; - /* Is it some type of real value? */ if (((type == vpiConstant || type == vpiParameter) && vpi_get(vpiConstType, info->items[*idx]) == vpiRealConst) || type == vpiRealVar ) { value.format = vpiRealVal; - vpi_get_value(info->items[*idx], &value); - if (value.format == vpiSuppressVal) { - vpi_printf("WARNING: incompatible value for %s%s.\n", - info->name, fmtb); - } else { - get_time_real(tbuf, value.value.real, prec, time_units); - if (ljust == 0) sprintf(result, "%*s", width, tbuf); - else sprintf(result, "%-*s", width, tbuf); - size = strlen(result) + 1; - } } else { value.format = vpiDecStrVal; - vpi_get_value(info->items[*idx], &value); - if (value.format == vpiSuppressVal) { - vpi_printf("WARNING: incompatible value for %s%s.\n", - info->name, fmtb); + } + vpi_get_value(info->items[*idx], &value); + if (value.format == vpiSuppressVal) { + vpi_printf("WARNING: %s:%d: incompatible value for %s%s.\n", + info->filename, info->lineno, info->name, fmtb); + } else { + char *tbuf; + PLI_INT32 time_units = vpi_get(vpiTimeUnit, info->scope); + unsigned swidth, free_flag = 0; + unsigned suff_len = strlen(timeformat_info.suff); + char *cp; + + /* The 512 (513-1 for EOL) is more than enough for any double + * value (309 digits plus a decimal point maximum). Because of + * scaling this could be larger. For decimal values you can + * have an arbitraty value so you can overflow the buffer, but + * for now we will assume the user will use this as intended + * (pass a time variable or the result of a time function). */ + tbuf = malloc((513+suff_len)*sizeof(char)); + if (prec == -1) prec = timeformat_info.prec; + if (value.format == vpiRealVal) { + get_time_real(tbuf, value.value.real, prec, time_units); } else { get_time(tbuf, value.value.str, prec, time_units); - if (ljust == 0) sprintf(result, "%*s", width, tbuf); - else sprintf(result, "%-*s", width, tbuf); - size = strlen(result) + 1; } + cp = tbuf; + swidth = strlen(tbuf); + + if (ld_zero == 1) { + /* No leading zeros are created by this conversion so just make + * the width 0 for this case. */ + if (width == -1) width = 0; + /* Pad with leading zeros. */ + else if (ljust == 0 && (signed)swidth < width) { + unsigned pad = (unsigned)width - swidth; + cp = malloc((width+1)*sizeof(char)); + memset(cp, '0', pad); + strcpy(cp+pad, tbuf); + free_flag = 1; + } + } + if (width == -1) width = timeformat_info.width; + + /* If the default buffer is too small make it big enough. */ + size = strlen(tbuf) + 1; + if ((signed)size < (width+1)) size = width+1; + if (size > ini_size) result = realloc(result, size*sizeof(char)); + + if (ljust == 0) sprintf(result, "%*s", width, cp); + else sprintf(result, "%-*s", width, cp); + if (free_flag) free(cp); + free(tbuf); + size = strlen(result) + 1; } } break; @@ -1625,16 +1749,18 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus, *idx += 1; if (ljust != 0 || plus != 0 || ld_zero != 0 || width != -1 || prec != -1) { - vpi_printf("WARNING: invalid format %s%s.\n", info->name, fmtb); + vpi_printf("WARNING: %s:%d: invalid format %s%s.\n", + info->filename, info->lineno, info->name, fmtb); } if (*idx >= info->nitems) { - vpi_printf("WARNING: missing argument for %s%s.\n", info->name, fmtb); + vpi_printf("WARNING: %s:%d: missing argument for %s%s.\n", + info->filename, info->lineno, info->name, fmtb); } else { value.format = vpiVectorVal; vpi_get_value(info->items[*idx], &value); if (value.format == vpiSuppressVal) { - vpi_printf("WARNING: incompatible value for %s%s.\n", info->name, - fmtb); + vpi_printf("WARNING: %s:%d: incompatible value for %s%s.\n", + info->filename, info->lineno, info->name, fmtb); } else { PLI_INT32 veclen, word, byte, bits; char *cp; @@ -1667,21 +1793,21 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus, case 'V': *idx += 1; if (plus != 0 || prec != -1) { - vpi_printf("WARNING: invalid format %s%s.\n", info->name, fmtb); + vpi_printf("WARNING: %s:%d: invalid format %s%s.\n", + info->filename, info->lineno, info->name, fmtb); } if (*idx >= info->nitems) { - vpi_printf("WARNING: missing argument for %s%s.\n", info->name, - fmtb); + vpi_printf("WARNING: %s:%d: missing argument for %s%s.\n", + info->filename, info->lineno, info->name, fmtb); } else { value.format = vpiStrengthVal; vpi_get_value(info->items[*idx], &value); if (value.format == vpiSuppressVal) { - vpi_printf("WARNING: incompatible value for %s%s.\n", info->name, - fmtb); + vpi_printf("WARNING: %s:%d: incompatible value for %s%s.\n", + info->filename, info->lineno, info->name, fmtb); } else { char tbuf[4], *rbuf; PLI_INT32 nbits; - unsigned rsize; int bit; /* If a width was not given use a width of zero. */ @@ -1690,9 +1816,10 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus, /* This is 4 chars for all but the last bit (strength + "_") * which only needs three chars (strength), but then you need * space for the EOS '\0', so it is just number of bits * 4. */ - rsize = nbits*4; - rbuf = malloc(rsize*sizeof(char)); - if (rsize > ini_size) result = realloc(result, rsize*sizeof(char)); + size = nbits*4; + rbuf = malloc(size*sizeof(char)); + if ((signed)size < (width+1)) size = width+1; + if (size > ini_size) result = realloc(result, size*sizeof(char)); strcpy(rbuf, ""); for (bit = nbits-1; bit >= 0; bit -= 1) { vpip_format_strength(tbuf, &value, bit); @@ -1713,16 +1840,18 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus, size = strlen(result) + 1; /* fallback value if errors */ if (ljust != 0 || plus != 0 || ld_zero != 0 || width != -1 || prec != -1) { - vpi_printf("WARNING: invalid format %s%s.\n", info->name, fmtb); + vpi_printf("WARNING: %s:%d: invalid format %s%s.\n", + info->filename, info->lineno, info->name, fmtb); } if (*idx >= info->nitems) { - vpi_printf("WARNING: missing argument for %s%s.\n", info->name, fmtb); + vpi_printf("WARNING: %s:%d: missing argument for %s%s.\n", + info->filename, info->lineno, info->name, fmtb); } else { value.format = vpiVectorVal; vpi_get_value(info->items[*idx], &value); if (value.format == vpiSuppressVal) { - vpi_printf("WARNING: incompatible value for %s%s.\n", info->name, - fmtb); + vpi_printf("WARNING: %s:%d: incompatible value for %s%s.\n", + info->filename, info->lineno, info->name, fmtb); } else { PLI_INT32 veclen, word, elem, bits, byte; char *cp; @@ -1754,7 +1883,8 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus, break; default: - vpi_printf("WARNING: unknown format %s%s.\n", info->name, fmtb); + vpi_printf("WARNING: %s:%d: unknown format %s%s.\n", + info->filename, info->lineno, info->name, fmtb); size = strlen(result) + 1; break; } @@ -1794,7 +1924,10 @@ static unsigned int get_format(char **rtn, char *fmt, else plus = 1; cp += 1; } - if (*cp == '0') ld_zero = 1; + if (*cp == '0') { + ld_zero = 1; + cp += 1; + } if (isdigit((int)*cp)) width = strtoul(cp, &cp, 10); if (*cp == '.') { cp += 1; @@ -1816,11 +1949,21 @@ static unsigned int get_format(char **rtn, char *fmt, static unsigned int get_numeric(char **rtn, struct strobe_cb_info *info, vpiHandle item) { - s_vpi_value value; + int size; + s_vpi_value val; - value.format = info->default_format; - vpi_get_value(item, &value); - *rtn = strdup(value.value.str); + val.format = info->default_format; + vpi_get_value(item, &val); + + switch(info->default_format){ + case vpiDecStrVal: + size = vpi_get_dec_size(item); + *rtn = malloc((size+1)*sizeof(char)); + sprintf(*rtn, "%*s", size, val.value.str); + break; + default: + *rtn = strdup(val.value.str); + } return strlen(*rtn); } @@ -1886,7 +2029,7 @@ static char *get_display(unsigned int *rtnsz, struct strobe_cb_info *info) case vpiRealVar: value.format = vpiRealVal; vpi_get_value(item, &value); - sprintf(buf, "%g", value.value.real); + sprintf(buf, "%#g", value.value.real); width = strlen(buf); rtn = realloc(rtn, (size+width)*sizeof(char)); memcpy(rtn+size-1, buf, width); @@ -1894,41 +2037,38 @@ static char *get_display(unsigned int *rtnsz, struct strobe_cb_info *info) case vpiSysFuncCall: func_name = vpi_get_str(vpiName, item); - /* This also gets the $stime function! */ + /* For now this also handles $stime */ if (strcmp(func_name, "$time") == 0) { value.format = vpiDecStrVal; vpi_get_value(item, &value); - get_time(buf, value.value.str, timeformat_info.prec, - vpi_get(vpiTimeUnit, info->scope)); - width = strlen(buf); - if (width < timeformat_info.width) width = timeformat_info.width; + width = strlen(value.value.str); + if (width < 20) width = 20; rtn = realloc(rtn, (size+width)*sizeof(char)); - sprintf(rtn+size-1, "%*s", width, buf); + sprintf(rtn+size-1, "%*s", width, value.value.str); } else if (strcmp(func_name, "$simtime") == 0) { value.format = vpiDecStrVal; vpi_get_value(item, &value); - /* $simtime does not need to be scaled. */ - get_time(buf, value.value.str, timeformat_info.prec, - timeformat_info.units); - width = strlen(buf); - if (width < timeformat_info.width) width = timeformat_info.width; + width = strlen(value.value.str); + if (width < 20) width = 20; rtn = realloc(rtn, (size+width)*sizeof(char)); - sprintf(rtn+size-1, "%*s", width, buf); + sprintf(rtn+size-1, "%*s", width, value.value.str); } else if (strcmp(func_name, "$realtime") == 0) { + /* Use the local scope precision. */ + int use_prec = vpi_get(vpiTimeUnit, info->scope) - + vpi_get(vpiTimePrecision, info->scope); + assert(use_prec >= 0); value.format = vpiRealVal; vpi_get_value(item, &value); - get_time_real(buf, value.value.real, timeformat_info.prec, - vpi_get(vpiTimeUnit, info->scope)); + sprintf(buf, "%.*f", use_prec, value.value.real); width = strlen(buf); - if (width < timeformat_info.width) width = timeformat_info.width; rtn = realloc(rtn, (size+width)*sizeof(char)); sprintf(rtn+size-1, "%*s", width, buf); } else { - vpi_printf("WARNING: %s does not support %s as an argument!\n", - info->name, func_name); + vpi_printf("WARNING: %s:%d: %s does not support %s as an argument!\n", + info->filename, info->lineno, info->name, func_name); strcpy(buf, ""); width = strlen(buf); rtn = realloc(rtn, (size+width)*sizeof(char)); @@ -1937,8 +2077,9 @@ static char *get_display(unsigned int *rtnsz, struct strobe_cb_info *info) break; default: - vpi_printf("WARNING: unknown argument type (%d) given to %s!\n", - vpi_get(vpiType, item), info->name); + vpi_printf("WARNING: %s:%d: unknown argument type (%d) given to %s!\n", + info->filename, info->lineno, vpi_get(vpiType, item), + info->name); result = ""; width = strlen(result); rtn = realloc(rtn, (size+width)*sizeof(char)); @@ -1952,6 +2093,48 @@ static char *get_display(unsigned int *rtnsz, struct strobe_cb_info *info) return rtn; } +#ifndef USE_OLD_DISPLAY +static PLI_INT32 sys_display_calltf(PLI_BYTE8 *name) +{ + vpiHandle callh, argv, scope; + struct strobe_cb_info info; + char* result; + unsigned int size, location=0; + + callh = vpi_handle(vpiSysTfCall, 0); + argv = vpi_iterate(vpiArgument, callh); + + scope = vpi_handle(vpiScope, callh); + assert(scope); + /* We could use vpi_get_str(vpiName, callh) to get the task name, but + * name is already defined. */ + info.name = name; + info.filename = strdup(vpi_get_str(vpiFile, callh)); + info.lineno = (int)vpi_get(vpiLineNo, callh); + info.default_format = get_default_format(name); + info.scope = scope; + array_from_iterator(&info, argv); + + /* Because %u and %z may put embedded NULL characters into the returned + * string strlen() may not match the real size! */ + result = get_display(&size, &info); + while (location < size) { + if (result[location] == '\0') { + my_mcd_printf(1, "\0"); + location += 1; + } else { + my_mcd_printf(1, "%s", &result[location]); + location += strlen(&result[location]); + } + } + if (strncmp(name,"$display",8) == 0) my_mcd_printf(1, "\n"); + + free(info.filename); + free(info.items); + return 0; +} +#endif + static PLI_INT32 sys_swrite_compiletf(PLI_BYTE8 *name) { vpiHandle callh = vpi_handle(vpiSysTfCall, 0); @@ -1960,7 +2143,9 @@ static PLI_INT32 sys_swrite_compiletf(PLI_BYTE8 *name) /* Check that there are arguments. */ if (argv == 0) { - vpi_printf("ERROR: %s requires at least one argument.\n", name); + vpi_printf("ERROR:%s:%d: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s requires at least one argument.\n", name); vpi_control(vpiFinish, 1); return 0; } @@ -1968,7 +2153,9 @@ static PLI_INT32 sys_swrite_compiletf(PLI_BYTE8 *name) /* The first argument must be a register. */ reg = vpi_scan(argv); /* This should never be zero. */ if (vpi_get(vpiType, reg) != vpiReg) { - vpi_printf("ERROR: %s's first argument must be a register.\n", name); + vpi_printf("ERROR:%s:%d: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s's first argument must be a register.\n", name); vpi_control(vpiFinish, 1); return 0; } @@ -1993,6 +2180,8 @@ static PLI_INT32 sys_swrite_calltf(PLI_BYTE8 *name) /* We could use vpi_get_str(vpiName, callh) to get the task name, but * name is already defined. */ info.name = name; + info.filename = strdup(vpi_get_str(vpiFile, callh)); + info.lineno = (int)vpi_get(vpiLineNo, callh); info.default_format = get_default_format(name); info.scope = scope; array_from_iterator(&info, argv); @@ -2003,10 +2192,11 @@ static PLI_INT32 sys_swrite_calltf(PLI_BYTE8 *name) val.format = vpiStringVal; vpi_put_value(reg, &val, 0, vpiNoDelay); if (size != strlen(val.value.str)) { - vpi_printf("WARNING: %s returned a value with an embedded NULL " - "(see %%u/%%z).\n", name); + vpi_printf("WARNING: %s:%d: %s returned a value with an embedded NULL " + "(see %%u/%%z).\n", info.filename, info.lineno, name); } + free(info.filename); free(info.items); return 0; } @@ -2020,7 +2210,9 @@ static PLI_INT32 sys_sformat_compiletf(PLI_BYTE8 *name) /* Check that there are arguments. */ if (argv == 0) { - vpi_printf("ERROR: %s requires at least two argument.\n", name); + vpi_printf("ERROR:%s:%d: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s requires at least two argument.\n", name); vpi_control(vpiFinish, 1); return 0; } @@ -2028,7 +2220,9 @@ static PLI_INT32 sys_sformat_compiletf(PLI_BYTE8 *name) /* The first argument must be a register. */ arg = vpi_scan(argv); /* This should never be zero. */ if (vpi_get(vpiType, arg) != vpiReg) { - vpi_printf("ERROR: %s's first argument must be a register.\n", name); + vpi_printf("ERROR:%s:%d: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s's first argument must be a register.\n", name); vpi_control(vpiFinish, 1); return 0; } @@ -2036,15 +2230,18 @@ static PLI_INT32 sys_sformat_compiletf(PLI_BYTE8 *name) /* The second argument must be a string or a register. */ arg = vpi_scan(argv); if (arg == 0) { - vpi_printf("ERROR: %s requires at least two argument.\n", name); + vpi_printf("ERROR:%s:%d: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s requires at least two argument.\n", name); vpi_control(vpiFinish, 1); return 0; } type = vpi_get(vpiType, arg); if (((type != vpiConstant && type != vpiParameter) || vpi_get(vpiConstType, arg) != vpiStringConst) && type != vpiReg) { - vpi_printf("ERROR: %s's second argument must be a string or a register.\n", - name); + vpi_printf("ERROR:%s:%d: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s's second argument must be a string or a register.\n", name); vpi_control(vpiFinish, 1); return 0; } @@ -2073,6 +2270,8 @@ static PLI_INT32 sys_sformat_calltf(PLI_BYTE8 *name) /* We could use vpi_get_str(vpiName, callh) to get the task name, but * name is already defined. */ info.name = name; + info.filename = strdup(vpi_get_str(vpiFile, callh)); + info.lineno = (int)vpi_get(vpiLineNo, callh); info.default_format = get_default_format(name); info.scope = scope; array_from_iterator(&info, argv); @@ -2081,7 +2280,8 @@ static PLI_INT32 sys_sformat_calltf(PLI_BYTE8 *name) free(fmt); if (idx+1< info.nitems) { - vpi_printf("WARNING: %s has %d extra argument(s).\n", name, + vpi_printf("WARNING: %s:%d: %s has %d extra argument(s).\n", + info.filename, info.lineno, name, info.nitems-idx-1); } @@ -2089,10 +2289,11 @@ static PLI_INT32 sys_sformat_calltf(PLI_BYTE8 *name) val.format = vpiStringVal; vpi_put_value(reg, &val, 0, vpiNoDelay); if (size != strlen(val.value.str)) { - vpi_printf("WARNING: %s returned a value with an embedded NULL " - "(see %%u/%%z).\n", name); + vpi_printf("WARNING: %s:%d: %s returned a value with an embedded NULL " + "(see %%u/%%z).\n", info.filename, info.lineno, name); } + free(info.filename); free(info.items); return 0; } @@ -2110,8 +2311,8 @@ static PLI_INT32 sys_end_of_compile(p_cb_data cb_data) static PLI_INT32 sys_timeformat_compiletf(PLI_BYTE8*xx) { - vpiHandle sys = vpi_handle(vpiSysTfCall, 0); - vpiHandle argv = vpi_iterate(vpiArgument, sys); + vpiHandle callh = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv = vpi_iterate(vpiArgument, callh); vpiHandle tmp; int lp;