diff --git a/README.txt b/README.txt index 918ece1a9..347b4ec6f 100644 --- a/README.txt +++ b/README.txt @@ -359,6 +359,22 @@ language that are defined. It is said that some commercial compilers do allow macro definitions to span library modules. That's just plain weird. + Width in %t Time Formats + + Standard Verilog does not allow width fields in the %t formats + of display strings. For example, this is illegal: + + $display("Time is %0t", %time); + + Standard Verilog instead relies on the $timeformat to + completely specify the format. + + Icarus Verilog allows the programmer to specify the field + with. The "%t" format in Icarus Verilog works exactly as it + does in standard Verilog. However, if the programmer chooses + to specify a minimum width, i.e. "%5t" Then for that display + Icarus Verilog will override the $timeformat minimum width and + use the explicit minimum width. 6.0 CREDITS diff --git a/vpi/sys_display.c b/vpi/sys_display.c index a401a8ad4..128f9a899 100644 --- a/vpi/sys_display.c +++ b/vpi/sys_display.c @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #if !defined(WINNT) && !defined(macintosh) -#ident "$Id: sys_display.c,v 1.37 2002/05/24 19:05:30 steve Exp $" +#ident "$Id: sys_display.c,v 1.38 2002/05/31 04:26:54 steve Exp $" #endif # include "config.h" @@ -28,6 +28,15 @@ # include # include +struct timeformat_info_s { + int units; + unsigned prec; + char*suff; + unsigned width; +}; + +struct timeformat_info_s timeformat_info = { 0, 0, 0, 20 }; + struct strobe_cb_info { char*name; int default_format; @@ -97,6 +106,81 @@ static void array_from_iterator(struct strobe_cb_info*info, vpiHandle argv) } } +static void format_time(unsigned mcd, int fsize, const char*value) +{ + char buf[256]; + const char*cp; + char*bp; + unsigned len; + int cnt; + + /* This is the time precision for the simulation. */ + int prec = vpi_get(vpiTimePrecision, 0); + + if (fsize < 0) + fsize = timeformat_info.width; + + bp = buf + sizeof buf; + cp = value + strlen(value); + + *--bp = 0; + + /* Draw the suffix into the buffer. */ + bp -= strlen(timeformat_info.suff); + strcpy(bp, timeformat_info.suff); + + /* Draw 0s to pad out the precision to the requested count. */ + cnt = timeformat_info.units - prec; + while (cnt < timeformat_info.prec) { + *--bp = '0'; + cnt += 1; + } + + /* Chop excess precision. */ + while (cnt > timeformat_info.prec) { + if (cp > value) + cp -= 1; + cnt -= 1; + prec += 1; + } + + /* Draw the digits of the time that are to the right of the + decimal point. Pad to the right with zeros if needed, to + get to the decimal point. */ + if (prec < timeformat_info.units) { + while (prec < timeformat_info.units) { + char val; + if (cp == value) + val = '0'; + else + val = *--cp; + + *--bp = val; + prec += 1; + } + + *--bp = '.'; + } + + /* Put the remaining characters to the left of the decimal + point. */ + while (cp > value) { + *--bp = *--cp; + } + + if (*bp == '.') + *--bp = '0'; + + /* Pad the string on the left to the requested minimum + width. Pad with spaces. */ + len = strlen(bp); + while (len < fsize) { + *--bp = ' '; + len += 1; + } + + vpi_mcd_printf(mcd, "%s", bp); +} /* * If $display discovers a string as a parameter, this function is @@ -300,6 +384,9 @@ static int format_str(vpiHandle scope, unsigned int mcd, break; case 't': + format_time(mcd, fsize, value.value.str); + break; + case 'd': if (fsize==-1){ // simple %d parameter. @@ -893,8 +980,70 @@ static int sys_fgetc_sizetf(char*x) return 32; } +static int sys_timeformat_compiletf(char *xx) +{ + vpiHandle sys = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv = vpi_iterate(vpiArgument, sys); + vpiHandle tmp; + + assert(argv); + tmp = vpi_scan(argv); + assert(tmp); + assert(vpi_get(vpiType, tmp) == vpiConstant); + + tmp = vpi_scan(argv); + assert(tmp); + assert(vpi_get(vpiType, tmp) == vpiConstant); + + tmp = vpi_scan(argv); + assert(tmp); + assert(vpi_get(vpiType, tmp) == vpiConstant); + + return 0; +} + +static int sys_timeformat_calltf(char *xx) +{ + s_vpi_value value; + vpiHandle sys = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv = vpi_iterate(vpiArgument, sys); + vpiHandle units = vpi_scan(argv); + vpiHandle prec = vpi_scan(argv); + vpiHandle suff = vpi_scan(argv); + vpiHandle wid = vpi_scan(argv); + + vpi_free_object(argv); + + value.format = vpiIntVal; + vpi_get_value(units, &value); + timeformat_info.units = value.value.integer; + + value.format = vpiIntVal; + vpi_get_value(prec, &value); + timeformat_info.prec = value.value.integer; + + value.format = vpiStringVal; + vpi_get_value(suff, &value); + timeformat_info.suff = strdup(value.value.str); + + value.format = vpiIntVal; + vpi_get_value(wid, &value); + timeformat_info.width = value.value.integer; + + return 0; +} + +static int sys_end_of_compile(p_cb_data cb_data) +{ + timeformat_info.suff = strdup(""); + timeformat_info.units = vpi_get(vpiTimePrecision, 0); + timeformat_info.width = 20; + return 0; +} + void sys_display_register() { + s_cb_data cb_data; s_vpi_systf_data tf_data; //============================== display @@ -1106,11 +1255,27 @@ void sys_display_register() tf_data.sizetf = sys_fgetc_sizetf; tf_data.user_data = "$fgetc"; vpi_register_systf(&tf_data); + + //============================ timeformat + tf_data.type = vpiSysTask; + tf_data.tfname = "$timeformat"; + tf_data.calltf = sys_timeformat_calltf; + tf_data.compiletf = sys_timeformat_compiletf; + tf_data.sizetf = 0; + vpi_register_systf(&tf_data); + + cb_data.reason = cbEndOfCompile; + cb_data.cb_rtn = sys_end_of_compile; + cb_data.user_data = "system"; + vpi_register_cb(&cb_data); } /* * $Log: sys_display.c,v $ + * Revision 1.38 2002/05/31 04:26:54 steve + * Add support for $timeformat. + * * Revision 1.37 2002/05/24 19:05:30 steve * support GCC __attributes__ for printf formats. *