iverilog/vpi/sys_display.c

1412 lines
36 KiB
C
Raw Normal View History

/*
* Copyright (c) 1999 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
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CVS_IDENT
#ident "$Id: sys_display.c,v 1.43 2002/08/22 23:34:52 steve Exp $"
#endif
# include "config.h"
# include "vpi_user.h"
# include <assert.h>
# include <string.h>
# include <ctype.h>
# include <stdlib.h>
2002-05-31 06:26:54 +02:00
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;
vpiHandle scope;
vpiHandle*items;
unsigned nitems;
};
// The number of decimal digits needed to represent a
// nr_bits binary number is floor(nr_bits*log_10(2))+1,
// where log_10(2) = 0.30102999566398.... and I approximate
// this transcendental number as 146/485, to avoid the vagaries
// of floating-point. The smallest nr_bits for which this
// approximation fails is 2621,
// 2621*log_10(2)=789.9996, but (2621*146+484)/485=790 (exactly).
// In cases like this, all that happens is we allocate one
// unneeded char for the output. I add a "L" suffix to 146
// to make sure the computation is done as long ints, otherwise
// on a 16-bit int machine (allowed by ISO C) we would mangle
// this computation for bit-length of 224. I'd like to put
// in a test for nr_bits < LONG_MAX/146, but don't know how
// to fail, other than crashing.
//
// In an April 2000 thread in comp.unix.programmer, with subject
// "integer -> string", I <LRDoolittle@lbl.gov> give the 28/93
// approximation, but overstate its accuracy: that version first
// fails when the number of bits is 289, not 671.
//
// This result does not include space for a trailing '\0', if any.
//
inline static int calc_dec_size(int nr_bits, int is_signed)
{
int r;
if (is_signed) --nr_bits;
r = (nr_bits * 146L + 484) / 485;
if (is_signed) ++r;
return r;
}
static int vpi_get_dec_size(vpiHandle item)
{
return calc_dec_size(
vpi_get(vpiSize, item),
vpi_get(vpiSigned, item)==1
);
}
static void array_from_iterator(struct strobe_cb_info*info, vpiHandle argv)
{
2001-03-18 01:31:32 +01:00
if (argv) {
vpiHandle item;
unsigned nitems = 1;
vpiHandle*items = malloc(sizeof(vpiHandle));
items[0] = vpi_scan(argv);
2002-07-23 04:41:15 +02:00
if (items[0] == 0) {
free(items);
info->nitems = 0;
info->items = 0;
return;
}
2001-03-18 01:31:32 +01:00
for (item = vpi_scan(argv) ; item ; item = vpi_scan(argv)) {
items = realloc(items, (nitems+1)*sizeof(vpiHandle));
items[nitems] = item;
nitems += 1;
}
info->nitems = nitems;
info->items = items;
2001-03-18 01:31:32 +01:00
} else {
info->nitems = 0;
info->items = 0;
}
}
2002-05-31 06:26:54 +02:00
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);
/* cnt is the number of digits that the simulation precision
units exceeds the time format units. For example, if the
simulation is in 1ps (-12) and $timeformat units is 1ns (-9)
then cnt is 3. */
2002-05-31 06:26:54 +02:00
cnt = timeformat_info.units - prec;
/* Draw 0s to pad out the precision to the requested count.
This accounts for the case that the difference between
simulation units and timeformat units is not enough for the
requested timeformat precision. */
while (cnt < (int)timeformat_info.prec) {
2002-05-31 06:26:54 +02:00
*--bp = '0';
cnt += 1;
}
/* Chop excess precision. This accounts for the case where the
simulation precision is greater then the timeformat
precision. Remove least significant digits from the integer
value of the time strings. */
while (cnt > (int)timeformat_info.prec) {
2002-05-31 06:26:54 +02:00
if (cp > value)
cp -= 1;
cnt -= 1;
prec += 1;
}
assert(cnt == timeformat_info.prec);
2002-05-31 06:26:54 +02:00
/* 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) {
2002-05-31 06:26:54 +02:00
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);
}
1999-10-08 19:47:49 +02:00
/*
* 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*fmt, int argc, vpiHandle*argv)
1999-11-06 23:16:50 +01:00
{
s_vpi_value value;
char buf[256];
char*cp = fmt;
char format_char = ' ';
1999-11-06 23:16:50 +01:00
int idx;
assert(fmt);
idx = 0;
while (*cp) {
size_t cnt = strcspn(cp, "%\\");
if (cnt > 0) {
if (cnt >= sizeof buf)
cnt = sizeof buf - 1;
strncpy(buf, cp, cnt);
buf[cnt] = 0;
vpi_mcd_printf(mcd, "%s", buf);
1999-11-06 23:16:50 +01:00
cp += cnt;
} else if (*cp == '%') {
int leading_zero = -1, fsize = -1, ffsize = -1;
int do_arg = 0;
1999-11-06 23:16:50 +01:00
cp += 1;
if (*cp == '0')
leading_zero=1;
if (isdigit((int)*cp))
1999-11-06 23:16:50 +01:00
fsize = strtoul(cp, &cp, 10);
2001-11-02 06:56:47 +01:00
if (*cp == '.') {
cp += 1;
ffsize = strtoul(cp, &cp, 10);
}
1999-11-06 23:16:50 +01:00
switch (*cp) {
case 0:
break;
1999-11-06 23:16:50 +01:00
case 'b':
case 'B':
if (ffsize != -1) {
vpi_printf("\nERROR: Illegal format \"%s\"\n", fmt);
fsize = -1;
}
format_char = 'b';
do_arg = 1;
1999-11-06 23:16:50 +01:00
value.format = vpiBinStrVal;
cp += 1;
break;
1999-11-06 23:16:50 +01:00
case 'd':
case 'D':
if (ffsize != -1) {
vpi_printf("\nERROR: Illegal format \"%s\"\n", fmt);
fsize = -1;
}
format_char = 'd';
do_arg = 1;
1999-11-06 23:16:50 +01:00
value.format = vpiDecStrVal;
cp += 1;
break;
1999-11-06 23:16:50 +01:00
case 'h':
case 'H':
case 'x':
case 'X':
if (ffsize != -1) {
vpi_printf("\nERROR: Illegal format \"%s\"\n", fmt);
fsize = -1;
}
format_char = 'h';
do_arg = 1;
1999-11-06 23:16:50 +01:00
value.format = vpiHexStrVal;
cp += 1;
break;
case 'c':
case 'C':
if (fsize != -1 && ffsize != -1) {
vpi_printf("\nERROR: Illegal format \"%s\"\n", fmt);
fsize = -1;
ffsize = -1;
}
format_char = 'c';
do_arg = 1;
value.format = vpiStringVal;
cp += 1;
break;
1999-11-06 23:16:50 +01:00
case 'm':
case 'M':
if (ffsize != -1) {
vpi_printf("\nERROR: Illegal format \"%s\"\n", fmt);
fsize = -1;
}
if (fsize == -1)
fsize = 0;
assert(scope);
vpi_mcd_printf(mcd, "%*s",
fsize,
vpi_get_str(vpiFullName, scope));
1999-11-06 23:16:50 +01:00
cp += 1;
break;
1999-11-06 23:16:50 +01:00
case 'o':
case 'O':
if (ffsize != -1) {
vpi_printf("\nERROR: Illegal format \"%s\"\n", fmt);
fsize = -1;
}
format_char = 'o';
do_arg = 1;
1999-11-06 23:16:50 +01:00
value.format = vpiOctStrVal;
cp += 1;
break;
2000-12-02 03:40:56 +01:00
case 's':
case 'S':
if (ffsize != -1) {
vpi_printf("\nERROR: Illegal format \"%s\"\n", fmt);
fsize = -1;
}
format_char = 's';
do_arg = 1;
2000-12-02 03:40:56 +01:00
value.format = vpiStringVal;
cp += 1;
break;
1999-11-06 23:16:50 +01:00
case 't':
case 'T':
if (ffsize != -1) {
vpi_printf("\nERROR: Illegal format \"%s\"\n", fmt);
fsize = -1;
}
format_char = 't';
do_arg = 1;
1999-11-06 23:16:50 +01:00
value.format = vpiDecStrVal;
cp += 1;
break;
1999-11-06 23:16:50 +01:00
case '%':
if (fsize != -1 && ffsize != -1) {
vpi_printf("\nERROR: Illegal format \"%s\"\n", fmt);
fsize = -1;
ffsize = -1;
}
vpi_mcd_printf(mcd, "%%");
1999-11-06 23:16:50 +01:00
cp += 1;
break;
case 'v':
case 'V':
case 'e':
case 'f':
case 'g':
// new Verilog 2001 format specifiers...
case 'l':
case 'L':
case 'u':
case 'U':
case 'z':
case 'Z':
vpi_printf("\nERROR: Unsupported format \"%s\"\n", fmt);
vpi_mcd_printf(mcd, "%c", *cp);
cp += 1;
break;
1999-11-06 23:16:50 +01:00
default:
vpi_printf("\nERROR: Illegal format \"%s\"\n", fmt);
vpi_mcd_printf(mcd, "%c", *cp);
1999-11-06 23:16:50 +01:00
cp += 1;
break;
}
/* If we encountered a numeric format string, then
grab the number value from the next parameter
and display it in the requested format. */
if (do_arg) {
if (idx >= argc) {
vpi_printf("\ntoo few arguments for format %s\n",
fmt);
} else {
vpi_get_value(argv[idx], &value);
if (value.format == vpiSuppressVal){
vpi_printf("\nERROR: parameter does not have a printable value!\n");
goto bail_out;
}
switch(format_char){
case 'c':
vpi_mcd_printf(mcd, "%c", value.value.str[strlen(value.value.str)-1]);
break;
case 't':
2002-05-31 06:26:54 +02:00
format_time(mcd, fsize, value.value.str);
break;
case 'd':
if (fsize==-1){
// simple %d parameter.
// Size is now determined by the width
// of the vector or integer
fsize = vpi_get_dec_size(argv[idx]);
}
vpi_mcd_printf(mcd, "%*s", fsize,
value.value.str);
break;
case 'b':
case 'h':
case 'x':
case 'o':
if (fsize==-1){
// For hex, oct and binary values, the string is already
// prefixed with the correct number of zeros...
vpi_mcd_printf(mcd, "%s", value.value.str);
}
else{
char* value_str = value.value.str;
if (leading_zero==1){
// Strip away all leading zeros from string
int i=0;
while(i< (strlen(value_str)-1) && value_str[i]=='0')
i++;
value_str += i;
}
vpi_mcd_printf(mcd, "%*s", fsize, value_str);
}
break;
case 's':
if (fsize==-1){
vpi_mcd_printf(mcd, "%s", value.value.str);
}
else{
char* value_str = value.value.str;
if (leading_zero==1){
// Remove leading spaces from the value
// string *except* if the argument is a
// constant string... (hey, that's how
// the commerical guys behave...)
if (!(vpi_get(vpiType, argv[idx]) == vpiConstant
&& vpi_get(vpiConstType, argv[idx]) == vpiStringConst)) {
int i=0;
// Strip away all leading zeros from string
while(i< (strlen(value_str)-1) && value_str[i]==' ')
i++;
value_str += i;
}
}
vpi_mcd_printf(mcd, "%*s", fsize, value_str);
}
break;
default:
if (fsize > 0)
vpi_mcd_printf(mcd, "%*s", fsize,
value.value.str);
else
vpi_mcd_printf(mcd, "%s",
value.value.str);
}
bail_out:
idx++;
}
}
1999-11-06 23:16:50 +01:00
} else {
cp += 1;
switch (*cp) {
case 0:
break;
case 'n':
vpi_mcd_printf(mcd, "\n");
1999-11-06 23:16:50 +01:00
cp += 1;
break;
case 't':
vpi_mcd_printf(mcd, "\t");
cp += 1;
break;
case '\\':
vpi_mcd_printf(mcd, "\\");
cp += 1;
break;
case '"':
vpi_mcd_printf(mcd, "\"");
cp += 1;
break;
1999-11-06 23:16:50 +01:00
default:
vpi_mcd_printf(mcd, "%c", *cp);
1999-11-06 23:16:50 +01:00
cp += 1;
}
}
}
return idx;
}
static void do_display(unsigned int mcd, struct strobe_cb_info*info)
{
1999-11-06 23:16:50 +01:00
s_vpi_value value;
int idx;
int size;
1999-11-06 23:16:50 +01:00
for (idx = 0 ; idx < info->nitems ; idx += 1) {
vpiHandle item = info->items[idx];
switch (vpi_get(vpiType, item)) {
case 0:
vpi_mcd_printf(mcd, " ");
1999-11-06 23:16:50 +01:00
break;
case vpiConstant:
if (vpi_get(vpiConstType, item) == vpiStringConst) {
value.format = vpiStringVal;
vpi_get_value(item, &value);
idx += format_str(info->scope, mcd, value.value.str,
1999-11-06 23:16:50 +01:00
info->nitems-idx-1,
1999-11-07 03:25:07 +01:00
info->items+idx+1);
1999-11-06 23:16:50 +01:00
} else {
value.format = vpiBinStrVal;
vpi_get_value(item, &value);
vpi_mcd_printf(mcd, "%s", value.value.str);
1999-11-06 23:16:50 +01:00
}
break;
case vpiNet:
case vpiReg:
case vpiIntegerVar:
case vpiMemoryWord:
value.format = info->default_format;
1999-11-06 23:16:50 +01:00
vpi_get_value(item, &value);
switch(info->default_format){
case vpiDecStrVal:
size = vpi_get_dec_size(item);
vpi_mcd_printf(mcd, "%*s", size, value.value.str);
break;
default:
vpi_mcd_printf(mcd, "%s", value.value.str);
}
1999-11-06 23:16:50 +01:00
break;
case vpiTimeVar:
value.format = vpiTimeVal;
vpi_get_value(item, &value);
vpi_mcd_printf(mcd, "%20u", value.value.time->low);
1999-11-06 23:16:50 +01:00
break;
default:
vpi_mcd_printf(mcd, "?");
1999-11-06 23:16:50 +01:00
break;
}
}
}
static int get_default_format(char *name)
{
int default_format;
switch(name[ strlen(name)-1 ]){
// writE/strobE or monitoR or displaY/fdisplaY
case 'e':
case 'r':
case 'y': default_format = vpiDecStrVal; break;
case 'h': default_format = vpiHexStrVal; break;
case 'o': default_format = vpiOctStrVal; break;
case 'b': default_format = vpiBinStrVal; break;
default:
assert(0);
}
return default_format;
}
static int sys_display_calltf(char *name)
{
struct strobe_cb_info info;
vpiHandle sys = vpi_handle(vpiSysTfCall, 0);
vpiHandle scope = vpi_handle(vpiScope, sys);
vpiHandle argv = vpi_iterate(vpiArgument, sys);
assert(scope);
info.default_format = get_default_format(name);
info.scope = scope;
array_from_iterator(&info, argv);
do_display(5, &info);
free(info.items);
if (strncmp(name,"$display",8) == 0)
vpi_mcd_printf(5, "\n");
return 0;
}
/*
* The strobe implementation takes the parameter handles that are
* passed to the calltf and puts them in to an array for safe
* keeping. That array (and other bookkeeping) is passed, via the
* struct_cb_info object, to the REadOnlySych function strobe_cb,
* where it is use to perform the actual formatting and printing.
*/
static int strobe_cb(p_cb_data cb)
{
struct strobe_cb_info*info = (struct strobe_cb_info*)cb->user_data;
do_display(1, info);
1999-11-06 23:16:50 +01:00
vpi_printf("\n");
free(info->name);
free(info->items);
free(info);
return 0;
}
static int sys_strobe_calltf(char*name)
{
struct t_cb_data cb;
struct t_vpi_time time;
1999-11-06 23:16:50 +01:00
vpiHandle sys = vpi_handle(vpiSysTfCall, 0);
vpiHandle scope = vpi_handle(vpiScope, sys);
1999-11-06 23:16:50 +01:00
vpiHandle argv = vpi_iterate(vpiArgument, sys);
struct strobe_cb_info*info = calloc(1, sizeof(struct strobe_cb_info));
1999-11-06 23:16:50 +01:00
array_from_iterator(info, argv);
1999-11-06 23:16:50 +01:00
info->name = strdup(name);
info->default_format = get_default_format(name);
info->scope= scope;
time.type = vpiSimTime;
time.low = 0;
time.high = 0;
cb.reason = cbReadOnlySynch;
cb.cb_rtn = strobe_cb;
cb.time = &time;
cb.obj = 0;
cb.value = 0;
1999-11-06 23:16:50 +01:00
cb.user_data = (char*)info;
vpi_register_cb(&cb);
return 0;
}
1999-11-07 03:25:07 +01:00
/*
* 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 };
1999-11-07 03:25:07 +01:00
static vpiHandle *monitor_callbacks = 0;
static int monitor_scheduled = 0;
static int monitor_enabled = 1;
1999-11-07 03:25:07 +01:00
static int monitor_cb_2(p_cb_data cb)
{
do_display(1, &monitor_info);
1999-11-07 03:25:07 +01:00
vpi_printf("\n");
monitor_scheduled = 0;
return 0;
}
/*
* The monitor_cb_1 callback is called when an even 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.
*/
1999-11-07 03:25:07 +01:00
static int monitor_cb_1(p_cb_data cause)
{
struct t_cb_data cb;
struct t_vpi_time time;
if (monitor_enabled == 0) return 0;
1999-11-07 03:25:07 +01:00
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;
1999-11-07 03:25:07 +01:00
vpi_register_cb(&cb);
return 0;
}
1999-10-29 05:37:22 +02:00
static int sys_monitor_calltf(char*name)
{
1999-11-07 03:25:07 +01:00
unsigned idx;
1999-10-29 05:37:22 +02:00
struct t_cb_data cb;
struct t_vpi_time time;
vpiHandle sys = vpi_handle(vpiSysTfCall, 0);
vpiHandle scope = vpi_handle(vpiScope, sys);
1999-10-29 05:37:22 +02:00
vpiHandle argv = vpi_iterate(vpiArgument, sys);
1999-11-07 03:25:07 +01:00
/* If there was a previous $monitor, then remove the calbacks
related to it. */
1999-11-07 03:25:07 +01:00
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. */
1999-11-07 03:25:07 +01:00
array_from_iterator(&monitor_info, argv);
monitor_info.name = strdup(name);
monitor_info.default_format = get_default_format(name);
monitor_info.scope = scope;
1999-11-07 03:25:07 +01:00
/* Attach callbacks to all the parameters that might change. */
1999-11-07 03:25:07 +01:00
monitor_callbacks = calloc(monitor_info.nitems, sizeof(vpiHandle));
1999-10-29 05:37:22 +02:00
time.type = vpiSuppressTime;
1999-11-07 03:25:07 +01:00
cb.reason = cbValueChange;
cb.cb_rtn = monitor_cb_1;
cb.time = &time;
cb.value = NULL;
1999-11-07 03:25:07 +01:00
for (idx = 0 ; idx < monitor_info.nitems ; idx += 1) {
switch (vpi_get(vpiType, monitor_info.items[idx])) {
case vpiNet:
case vpiReg:
case vpiIntegerVar:
/* 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);
1999-11-07 03:25:07 +01:00
cb.obj = monitor_info.items[idx];
monitor_callbacks[idx] = vpi_register_cb(&cb);
break;
}
}
1999-10-29 05:37:22 +02:00
/* 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 int sys_monitoron_calltf(char*name)
{
monitor_enabled = 1;
monitor_cb_1(0);
return 0;
}
static int sys_monitoroff_calltf(char*name)
{
monitor_enabled = 0;
1999-10-29 05:37:22 +02:00
return 0;
}
/*
* Implement the $fopen system function.
*/
static int sys_fopen_calltf(char *name)
{
2001-03-22 03:23:17 +01:00
s_vpi_value val, value, modevalue;
unsigned char *mode_string;
vpiHandle call_handle = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, call_handle);
2001-06-25 05:11:41 +02:00
vpiHandle item = argv ? vpi_scan(argv) : 0;
vpiHandle mode = item ? vpi_scan(argv) : 0;
if (item == 0) {
vpi_printf("%s: file name parameter missing.\n", name);
return 0;
}
2001-06-25 05:11:41 +02:00
if (mode == 0) {
argv = 0;
}
if (vpi_get(vpiType, item) != vpiConstant) {
vpi_printf("ERROR: %s parameter must be a constant\n", name);
vpi_free_object(argv);
return 0;
}
if (vpi_get(vpiConstType, item) != vpiStringConst) {
2001-02-10 20:50:33 +01:00
vpi_printf("ERROR: %s parameter must be a string.\n", name);
vpi_free_object(argv);
return 0;
}
2001-03-22 03:23:17 +01:00
if (mode == 0) {
mode_string = "w";
} else {
if (vpi_get(vpiType, mode) != vpiConstant) {
vpi_printf("ERROR: %s parameter must be a constant\n", name);
vpi_free_object(argv);
return 0;
}
if (vpi_get(vpiConstType, mode) != vpiStringConst) {
vpi_printf("ERROR: %s parameter must be a string.\n", name);
vpi_free_object(argv);
return 0;
}
modevalue.format = vpiStringVal;
vpi_get_value(mode, &modevalue);
mode_string = modevalue.value.str;
}
value.format = vpiStringVal;
vpi_get_value(item, &value);
val.format = vpiIntVal;
2001-03-22 03:23:17 +01:00
val.value.integer = vpi_mcd_open_x( value.value.str, mode_string );
vpi_put_value(call_handle, &val, 0, vpiNoDelay);
return 0;
}
static int sys_fopen_sizetf(char*x)
{
return 32;
}
/* Implement $fdisplay and $fwrite.
* Perhaps this could be merged into sys_display_calltf.
*/
static int sys_fdisplay_calltf(char *name)
{
struct strobe_cb_info info;
unsigned int mcd;
int type;
s_vpi_value value;
vpiHandle sys = vpi_handle(vpiSysTfCall, 0);
2001-11-02 06:56:47 +01:00
vpiHandle scope = vpi_handle(vpiScope, sys);
vpiHandle argv = vpi_iterate(vpiArgument, sys);
vpiHandle item = vpi_scan(argv);
if (item == 0) {
vpi_printf("%s: mcd parameter missing.\n", name);
return 0;
}
type = vpi_get(vpiType, item);
switch (type) {
case vpiReg:
case vpiRealVal:
case vpiIntegerVar:
break;
default:
vpi_printf("ERROR: %s mcd parameter must be of integral", name);
vpi_printf(", got vpiType=%d\n", type);
vpi_free_object(argv);
return 0;
}
value.format = vpiIntVal;
vpi_get_value(item, &value);
mcd = value.value.integer;
2001-11-02 06:56:47 +01:00
assert(scope);
info.default_format = get_default_format(name);
2001-11-02 06:56:47 +01:00
info.scope = scope;
array_from_iterator(&info, argv);
do_display(mcd, &info);
free(info.items);
if (strncmp(name,"$fdisplay",9) == 0)
vpi_mcd_printf(mcd, "\n");
return 0;
}
/*
* Implement $fclose system function
*/
static int sys_fclose_calltf(char *name)
{
unsigned int mcd;
int type;
s_vpi_value value;
vpiHandle sys = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, sys);
vpiHandle item = vpi_scan(argv);
if (item == 0) {
vpi_printf("%s: mcd parameter missing.\n", name);
return 0;
}
type = vpi_get(vpiType, item);
switch (type) {
case vpiReg:
case vpiRealVal:
case vpiIntegerVar:
break;
default:
vpi_printf("ERROR: %s mcd parameter must be of integral type",
name);
vpi_printf(", got vpiType=%d\n", type);
vpi_free_object(argv);
return 0;
}
value.format = vpiIntVal;
vpi_get_value(item, &value);
mcd = value.value.integer;
vpi_mcd_close(mcd);
return 0;
}
2001-03-22 03:23:17 +01:00
static int sys_fputc_calltf(char *name)
{
unsigned int mcd;
int type;
unsigned char x;
s_vpi_value value, xvalue;
vpiHandle sys = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, sys);
vpiHandle item = vpi_scan(argv);
if (item == 0) {
vpi_printf("%s: mcd parameter missing.\n", name);
return 0;
}
type = vpi_get(vpiType, item);
switch (type) {
case vpiReg:
case vpiRealVal:
case vpiIntegerVar:
break;
default:
vpi_printf("ERROR: %s mcd parameter must be of integral", name);
vpi_printf(", got vpiType=%d\n", type);
vpi_free_object(argv);
return 0;
2001-03-22 03:23:17 +01:00
}
value.format = vpiIntVal;
vpi_get_value(item, &value);
mcd = value.value.integer;
item = vpi_scan(argv);
xvalue.format = vpiIntVal;
vpi_get_value(item, &xvalue);
x = xvalue.value.integer;
return vpi_mcd_fputc( mcd, x );
}
static int sys_fgetc_calltf(char *name)
{
unsigned int mcd;
int type;
s_vpi_value value, rval;
vpiHandle sys = vpi_handle(vpiSysTfCall, 0);
vpiHandle argv = vpi_iterate(vpiArgument, sys);
vpiHandle item = vpi_scan(argv);
if (item == 0) {
vpi_printf("%s: mcd parameter missing.\n", name);
return 0;
}
type = vpi_get(vpiType, item);
switch (type) {
case vpiReg:
case vpiRealVal:
case vpiIntegerVar:
break;
default:
vpi_printf("ERROR: %s mcd parameter must be of integral", name);
vpi_printf(", got vpiType=%d\n", type);
vpi_free_object(argv);
return 0;
2001-03-22 03:23:17 +01:00
}
value.format = vpiIntVal;
vpi_get_value(item, &value);
mcd = value.value.integer;
rval.format = vpiIntVal;
rval.value.integer = vpi_mcd_fgetc( mcd );
vpi_put_value(sys, &rval, 0, vpiNoDelay);
return 0;
}
static int sys_fgetc_sizetf(char*x)
{
return 32;
}
2002-05-31 06:26:54 +02:00
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()
{
2002-05-31 06:26:54 +02:00
s_cb_data cb_data;
s_vpi_systf_data tf_data;
//============================== display
tf_data.type = vpiSysTask;
tf_data.tfname = "$display";
tf_data.calltf = sys_display_calltf;
tf_data.compiletf = 0;
tf_data.sizetf = 0;
tf_data.user_data = "$display";
vpi_register_systf(&tf_data);
tf_data.type = vpiSysTask;
tf_data.tfname = "$displayh";
tf_data.calltf = sys_display_calltf;
tf_data.compiletf = 0;
tf_data.sizetf = 0;
tf_data.user_data = "$displayh";
vpi_register_systf(&tf_data);
tf_data.type = vpiSysTask;
tf_data.tfname = "$displayo";
tf_data.calltf = sys_display_calltf;
tf_data.compiletf = 0;
tf_data.sizetf = 0;
tf_data.user_data = "$displayo";
vpi_register_systf(&tf_data);
tf_data.type = vpiSysTask;
tf_data.tfname = "$displayb";
tf_data.calltf = sys_display_calltf;
tf_data.compiletf = 0;
tf_data.sizetf = 0;
tf_data.user_data = "$displayb";
vpi_register_systf(&tf_data);
//============================== write
tf_data.type = vpiSysTask;
tf_data.tfname = "$write";
tf_data.calltf = sys_display_calltf;
tf_data.compiletf = 0;
tf_data.sizetf = 0;
tf_data.user_data = "$write";
vpi_register_systf(&tf_data);
tf_data.type = vpiSysTask;
tf_data.tfname = "$writeh";
tf_data.calltf = sys_display_calltf;
tf_data.compiletf = 0;
tf_data.sizetf = 0;
tf_data.user_data = "$writeh";
vpi_register_systf(&tf_data);
tf_data.type = vpiSysTask;
tf_data.tfname = "$writeo";
tf_data.calltf = sys_display_calltf;
tf_data.compiletf = 0;
tf_data.sizetf = 0;
tf_data.user_data = "$writeo";
vpi_register_systf(&tf_data);
tf_data.type = vpiSysTask;
tf_data.tfname = "$writeb";
tf_data.calltf = sys_display_calltf;
tf_data.compiletf = 0;
tf_data.sizetf = 0;
tf_data.user_data = "$writeb";
vpi_register_systf(&tf_data);
//============================== strobe
tf_data.type = vpiSysTask;
tf_data.tfname = "$strobe";
tf_data.calltf = sys_strobe_calltf;
tf_data.compiletf = 0;
tf_data.sizetf = 0;
tf_data.user_data = "$strobe";
vpi_register_systf(&tf_data);
1999-10-29 05:37:22 +02:00
tf_data.type = vpiSysTask;
tf_data.tfname = "$strobeh";
tf_data.calltf = sys_strobe_calltf;
tf_data.compiletf = 0;
tf_data.sizetf = 0;
tf_data.user_data = "$strobeh";
vpi_register_systf(&tf_data);
tf_data.type = vpiSysTask;
tf_data.tfname = "$strobeo";
tf_data.calltf = sys_strobe_calltf;
tf_data.compiletf = 0;
tf_data.sizetf = 0;
tf_data.user_data = "$strobeo";
vpi_register_systf(&tf_data);
tf_data.type = vpiSysTask;
tf_data.tfname = "$strobeb";
tf_data.calltf = sys_strobe_calltf;
tf_data.compiletf = 0;
tf_data.sizetf = 0;
tf_data.user_data = "$strobeb";
vpi_register_systf(&tf_data);
//============================== monitor
1999-10-29 05:37:22 +02:00
tf_data.type = vpiSysTask;
tf_data.tfname = "$monitor";
tf_data.calltf = sys_monitor_calltf;
tf_data.compiletf = 0;
tf_data.sizetf = 0;
tf_data.user_data = "$monitor";
vpi_register_systf(&tf_data);
tf_data.type = vpiSysTask;
tf_data.tfname = "$monitorh";
tf_data.calltf = sys_monitor_calltf;
tf_data.compiletf = 0;
tf_data.sizetf = 0;
tf_data.user_data = "$monitorh";
vpi_register_systf(&tf_data);
tf_data.type = vpiSysTask;
tf_data.tfname = "$monitoro";
tf_data.calltf = sys_monitor_calltf;
tf_data.compiletf = 0;
tf_data.sizetf = 0;
tf_data.user_data = "$monitoro";
vpi_register_systf(&tf_data);
tf_data.type = vpiSysTask;
tf_data.tfname = "$monitorb";
tf_data.calltf = sys_monitor_calltf;
tf_data.compiletf = 0;
tf_data.sizetf = 0;
tf_data.user_data = "$monitorb";
vpi_register_systf(&tf_data);
tf_data.type = vpiSysTask;
tf_data.tfname = "$monitoron";
tf_data.calltf = sys_monitoron_calltf;
tf_data.compiletf = 0;
tf_data.sizetf = 0;
tf_data.user_data = "$monitoron";
vpi_register_systf(&tf_data);
tf_data.type = vpiSysTask;
tf_data.tfname = "$monitoroff";
tf_data.calltf = sys_monitoroff_calltf;
tf_data.compiletf = 0;
tf_data.sizetf = 0;
tf_data.user_data = "$monitoroff";
vpi_register_systf(&tf_data);
//============================== fopen
tf_data.type = vpiSysFunc;
tf_data.tfname = "$fopen";
tf_data.calltf = sys_fopen_calltf;
tf_data.compiletf = 0;
tf_data.sizetf = sys_fopen_sizetf;
tf_data.user_data = "$fopen";
vpi_register_systf(&tf_data);
//============================== fclose
tf_data.type = vpiSysTask;
tf_data.tfname = "$fclose";
tf_data.calltf = sys_fclose_calltf;
tf_data.compiletf = 0;
tf_data.sizetf = 0;
tf_data.user_data = "$fclose";
vpi_register_systf(&tf_data);
//============================== fdisplay
tf_data.type = vpiSysTask;
tf_data.tfname = "$fdisplay";
tf_data.calltf = sys_fdisplay_calltf;
tf_data.compiletf = 0;
tf_data.sizetf = 0;
tf_data.user_data = "$fdisplay";
vpi_register_systf(&tf_data);
tf_data.type = vpiSysTask;
tf_data.tfname = "$fdisplayh";
tf_data.calltf = sys_fdisplay_calltf;
tf_data.compiletf = 0;
tf_data.sizetf = 0;
tf_data.user_data = "$fdisplayh";
vpi_register_systf(&tf_data);
tf_data.type = vpiSysTask;
tf_data.tfname = "$fdisplayo";
tf_data.calltf = sys_fdisplay_calltf;
tf_data.compiletf = 0;
tf_data.sizetf = 0;
tf_data.user_data = "$fdisplayo";
vpi_register_systf(&tf_data);
tf_data.type = vpiSysTask;
tf_data.tfname = "$fdisplayb";
tf_data.calltf = sys_fdisplay_calltf;
tf_data.compiletf = 0;
tf_data.sizetf = 0;
tf_data.user_data = "$fdisplayb";
vpi_register_systf(&tf_data);
//============================== fwrite
tf_data.type = vpiSysTask;
tf_data.tfname = "$fwrite";
tf_data.calltf = sys_fdisplay_calltf;
tf_data.compiletf = 0;
tf_data.sizetf = 0;
tf_data.user_data = "$fwrite";
vpi_register_systf(&tf_data);
2001-03-22 03:23:17 +01:00
//============================== fputc
2001-03-22 03:23:17 +01:00
tf_data.type = vpiSysTask;
tf_data.tfname = "$fputc";
tf_data.calltf = sys_fputc_calltf;
tf_data.compiletf = 0;
tf_data.sizetf = 0;
tf_data.user_data = "$fputc";
vpi_register_systf(&tf_data);
//============================== fgetc
2001-03-22 03:23:17 +01:00
tf_data.type = vpiSysFunc;
tf_data.tfname = "$fgetc";
tf_data.calltf = sys_fgetc_calltf;
tf_data.compiletf = 0;
tf_data.sizetf = sys_fgetc_sizetf;
tf_data.user_data = "$fgetc";
vpi_register_systf(&tf_data);
2002-05-31 06:26:54 +02:00
//============================ 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.43 2002/08/22 23:34:52 steve
* Watch signed comparisons, that lead to infinite loops.
*
* Revision 1.42 2002/08/12 01:35:04 steve
* conditional ident string using autoconfig.
*
* Revision 1.41 2002/07/25 03:35:51 steve
* Add monitoron and monitoroff system tasks.
*
2002-07-23 04:41:15 +02:00
* Revision 1.40 2002/07/23 02:41:15 steve
* Fix display of no arguments.
*
* Revision 1.39 2002/06/21 04:59:36 steve
* Carry integerness throughout the compilation.
*
2002-05-31 06:26:54 +02:00
* 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.
*
2002-04-06 22:25:45 +02:00
* Revision 1.36 2002/04/06 20:25:45 steve
* cbValueChange automatically replays.
*
* Revision 1.35 2002/02/06 04:50:04 steve
* Detect and skip suppressed values in display
*
* Revision 1.34 2002/01/22 00:18:10 steve
* Better calcuation of dec string width (Larry Doolittle)
*
* Revision 1.33 2002/01/15 03:23:34 steve
* Default widths pad out as per the standard,
* add $displayb/o/h et al., and some better
* error messages for incorrect formats.
*
* Revision 1.32 2002/01/11 04:48:01 steve
* Add the %c format, and some warning messages.
*
2001-11-02 06:56:47 +01:00
* Revision 1.31 2001/11/02 05:56:47 steve
* initialize scope for %m in $fdisplay.
*
* Revision 1.30 2001/10/25 04:19:53 steve
* VPI support for callback to return values.
*/