2003-03-07 03:44:33 +01:00
|
|
|
/*
|
2013-10-11 19:48:01 +02:00
|
|
|
* Copyright (c) 2003-2013 Michael Ruff (mruff at chiaro.com)
|
2003-03-07 03:44:33 +01:00
|
|
|
*
|
|
|
|
|
* 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
|
2012-08-29 03:41:23 +02:00
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
2003-03-07 03:44:33 +01:00
|
|
|
*/
|
|
|
|
|
|
2009-02-27 00:22:21 +01:00
|
|
|
# include "sys_priv.h"
|
2003-03-07 03:44:33 +01:00
|
|
|
# include <stdio.h>
|
2003-03-17 22:59:54 +01:00
|
|
|
# include <string.h>
|
2003-03-07 03:44:33 +01:00
|
|
|
# include <math.h>
|
|
|
|
|
|
2003-03-17 22:59:54 +01:00
|
|
|
static double bits2double(PLI_UINT32 bits[2])
|
|
|
|
|
{
|
|
|
|
|
union conv {
|
|
|
|
|
double rval;
|
|
|
|
|
unsigned char bval[sizeof(double)];
|
|
|
|
|
} conv;
|
|
|
|
|
|
|
|
|
|
#ifdef WORDS_BIGENDIAN
|
|
|
|
|
conv.bval[7] = (bits[0] >> 0) & 0xff;
|
|
|
|
|
conv.bval[6] = (bits[0] >> 8) & 0xff;
|
|
|
|
|
conv.bval[5] = (bits[0] >> 16) & 0xff;
|
|
|
|
|
conv.bval[4] = (bits[0] >> 24) & 0xff;
|
|
|
|
|
conv.bval[3] = (bits[1] >> 0) & 0xff;
|
|
|
|
|
conv.bval[2] = (bits[1] >> 8) & 0xff;
|
|
|
|
|
conv.bval[1] = (bits[1] >> 16) & 0xff;
|
|
|
|
|
conv.bval[0] = (bits[1] >> 24) & 0xff;
|
|
|
|
|
#else
|
|
|
|
|
conv.bval[0] = (bits[0] >> 0) & 0xff;
|
|
|
|
|
conv.bval[1] = (bits[0] >> 8) & 0xff;
|
|
|
|
|
conv.bval[2] = (bits[0] >> 16) & 0xff;
|
|
|
|
|
conv.bval[3] = (bits[0] >> 24) & 0xff;
|
|
|
|
|
conv.bval[4] = (bits[1] >> 0) & 0xff;
|
|
|
|
|
conv.bval[5] = (bits[1] >> 8) & 0xff;
|
|
|
|
|
conv.bval[6] = (bits[1] >> 16) & 0xff;
|
|
|
|
|
conv.bval[7] = (bits[1] >> 24) & 0xff;
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
return conv.rval;
|
|
|
|
|
}
|
|
|
|
|
|
2003-03-07 03:44:33 +01:00
|
|
|
static void double2bits(double real, PLI_UINT32 bits[2])
|
|
|
|
|
{
|
|
|
|
|
union conv {
|
|
|
|
|
double rval;
|
|
|
|
|
unsigned char bval[sizeof(double)];
|
|
|
|
|
} conv;
|
|
|
|
|
|
|
|
|
|
conv.rval = real;
|
|
|
|
|
|
|
|
|
|
#ifdef WORDS_BIGENDIAN
|
|
|
|
|
bits[0] = conv.bval[7]
|
|
|
|
|
| (conv.bval[6] << 8)
|
|
|
|
|
| (conv.bval[5] <<16)
|
|
|
|
|
| (conv.bval[4] <<24);
|
|
|
|
|
bits[1] = conv.bval[3]
|
|
|
|
|
| (conv.bval[2] << 8)
|
|
|
|
|
| (conv.bval[1] <<16)
|
|
|
|
|
| (conv.bval[0] <<24);
|
|
|
|
|
#else
|
|
|
|
|
bits[0] = conv.bval[0]
|
|
|
|
|
| (conv.bval[1] << 8)
|
|
|
|
|
| (conv.bval[2] <<16)
|
|
|
|
|
| (conv.bval[3] <<24);
|
|
|
|
|
bits[1] = conv.bval[4]
|
|
|
|
|
| (conv.bval[5] << 8)
|
|
|
|
|
| (conv.bval[6] <<16)
|
|
|
|
|
| (conv.bval[7] <<24);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
2008-01-07 04:50:59 +01:00
|
|
|
static void error_message(vpiHandle callh, const char* msg)
|
|
|
|
|
{
|
Rework $plusarg routines.
This patch addresses a number of issues:
Rewrote the $test$plusargs and $value$plusargs routines to have
better error/warning messages, to support runtime strings, to
correctly load bit based values (truncating, padding, negative
value), added support for the real formats using strtod() and
added "x/X" as an alias for "h/H" to match the other part of
Icarus.
Rewrite the vpip_{bin,oct,hex}_str_to_vec4 routines to ignore
embedded "_" characters. Add support for a negative value and
set the entire value to 'bx if an invalid digit is found. A
warning is printed for this case.
Rewrite vpip_dec_str_to_vec4 to ignore embedded "_" characters,
to support a single "x" or "z" constant and to return 'bx if an
invalid digit is found. A warning is printed for this case.
It simplifies the system task/functions error/warning messages.
It removes the signed flag for the bin and dec string conversions.
This was not being used (was always false) and the new negative
value support makes this obsolete.
Add support for a real variable to handle Bin, Oct, Dec and Hex
strings. They are converted into a vvp_vector4_t which is then
converted to a real value.
Add support for setting a bit based value using a real value.
Removed an unneeded rfp signal in vpip_make_reg()
2008-11-13 22:28:19 +01:00
|
|
|
vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh),
|
2008-01-07 04:50:59 +01:00
|
|
|
(int)vpi_get(vpiLineNo, callh));
|
|
|
|
|
vpi_printf(msg, vpi_get_str(vpiName, callh));
|
|
|
|
|
vpi_control(vpiFinish, 1);
|
|
|
|
|
}
|
|
|
|
|
|
2007-03-14 05:05:51 +01:00
|
|
|
static PLI_INT32 sizetf_32 (PLI_BYTE8*x) { return 32; }
|
|
|
|
|
static PLI_INT32 sizetf_64 (PLI_BYTE8*x) { return 64; }
|
2003-03-07 03:44:33 +01:00
|
|
|
|
2010-10-04 18:31:01 +02:00
|
|
|
static PLI_INT32 sys_convert_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name)
|
2003-03-07 03:44:33 +01:00
|
|
|
{
|
2008-01-07 04:50:59 +01:00
|
|
|
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
|
|
|
|
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
|
|
|
|
vpiHandle arg;
|
|
|
|
|
|
|
|
|
|
/* Check that there is an argument. */
|
|
|
|
|
if (argv == 0) {
|
|
|
|
|
error_message(callh, "%s requires one argument.\n");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2003-03-07 03:44:33 +01:00
|
|
|
|
2008-01-07 04:50:59 +01:00
|
|
|
/* In Icarus if we have an argv we have at least one argument. */
|
2003-03-17 22:59:54 +01:00
|
|
|
arg = vpi_scan(argv);
|
2003-03-07 03:44:33 +01:00
|
|
|
|
2008-01-07 04:50:59 +01:00
|
|
|
/* Validate the argument. Only $bitstoreal for now. */
|
2003-03-17 22:59:54 +01:00
|
|
|
if (!strcmp("$bitstoreal", name) && vpi_get(vpiSize, arg) != 64) {
|
2008-01-07 04:50:59 +01:00
|
|
|
error_message(callh, "%s requires a 64-bit argument.\n");
|
|
|
|
|
return 0;
|
2003-03-17 22:59:54 +01:00
|
|
|
}
|
|
|
|
|
|
2008-01-07 04:50:59 +01:00
|
|
|
/* Save the argument away to make the calltf faster. */
|
|
|
|
|
vpi_put_userdata(callh, (void *) arg);
|
|
|
|
|
|
|
|
|
|
/* These functions only take one argument. */
|
2009-02-27 00:22:21 +01:00
|
|
|
check_for_extra_args(argv, callh, name, "one argument", 0);
|
2003-03-17 22:59:54 +01:00
|
|
|
|
2008-01-07 04:50:59 +01:00
|
|
|
return 0;
|
2003-03-17 22:59:54 +01:00
|
|
|
}
|
|
|
|
|
|
2010-10-04 18:31:01 +02:00
|
|
|
static PLI_INT32 sys_bitstoreal_calltf(ICARUS_VPI_CONST PLI_BYTE8*user)
|
2003-03-17 22:59:54 +01:00
|
|
|
{
|
2008-01-07 04:50:59 +01:00
|
|
|
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
|
|
|
|
vpiHandle arg = (vpiHandle) vpi_get_userdata(callh);
|
2003-03-17 22:59:54 +01:00
|
|
|
s_vpi_value value;
|
|
|
|
|
|
|
|
|
|
PLI_UINT32 bits[2];
|
|
|
|
|
|
|
|
|
|
/* get value */
|
|
|
|
|
value.format = vpiVectorVal;
|
|
|
|
|
vpi_get_value(arg, &value);
|
|
|
|
|
|
|
|
|
|
/* convert */
|
|
|
|
|
bits[0] = (value.value.vector[0]).aval;
|
|
|
|
|
bits[1] = (value.value.vector[1]).aval;
|
|
|
|
|
value.value.real = bits2double(bits);
|
|
|
|
|
value.format = vpiRealVal;
|
|
|
|
|
|
|
|
|
|
/* return converted value */
|
2008-01-07 04:50:59 +01:00
|
|
|
vpi_put_value(callh, &value, 0, vpiNoDelay);
|
2003-03-17 22:59:54 +01:00
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2010-10-04 18:31:01 +02:00
|
|
|
static PLI_INT32 sys_itor_calltf(ICARUS_VPI_CONST PLI_BYTE8*user)
|
2003-03-17 22:59:54 +01:00
|
|
|
{
|
2008-01-07 04:50:59 +01:00
|
|
|
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
|
|
|
|
vpiHandle arg = (vpiHandle) vpi_get_userdata(callh);
|
2003-03-17 22:59:54 +01:00
|
|
|
s_vpi_value value;
|
|
|
|
|
|
|
|
|
|
/* get value */
|
|
|
|
|
value.format = vpiIntVal;
|
|
|
|
|
vpi_get_value(arg, &value);
|
|
|
|
|
|
|
|
|
|
/* convert */
|
2013-10-11 19:48:01 +02:00
|
|
|
value.value.real = value.value.integer;
|
2003-03-17 22:59:54 +01:00
|
|
|
value.format = vpiRealVal;
|
|
|
|
|
|
|
|
|
|
/* return converted value */
|
2008-01-07 04:50:59 +01:00
|
|
|
vpi_put_value(callh, &value, 0, vpiNoDelay);
|
2003-03-17 22:59:54 +01:00
|
|
|
|
2003-03-07 03:44:33 +01:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2010-10-04 18:31:01 +02:00
|
|
|
static PLI_INT32 sys_realtobits_calltf(ICARUS_VPI_CONST PLI_BYTE8*user)
|
2003-03-07 03:44:33 +01:00
|
|
|
{
|
2008-01-07 04:50:59 +01:00
|
|
|
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
|
|
|
|
vpiHandle arg = (vpiHandle) vpi_get_userdata(callh);
|
2003-03-07 03:44:33 +01:00
|
|
|
s_vpi_value value;
|
|
|
|
|
static struct t_vpi_vecval res[2];
|
|
|
|
|
|
|
|
|
|
PLI_UINT32 bits[2];
|
|
|
|
|
|
2003-03-11 00:40:10 +01:00
|
|
|
/* get value */
|
2003-03-07 03:44:33 +01:00
|
|
|
value.format = vpiRealVal;
|
|
|
|
|
vpi_get_value(arg, &value);
|
|
|
|
|
|
2003-03-11 00:40:10 +01:00
|
|
|
/* convert */
|
2003-03-07 03:44:33 +01:00
|
|
|
double2bits(value.value.real, bits);
|
|
|
|
|
|
|
|
|
|
res[0].aval = bits[0];
|
|
|
|
|
res[0].bval = 0;
|
|
|
|
|
res[1].aval = bits[1];
|
|
|
|
|
res[1].bval = 0;
|
|
|
|
|
|
|
|
|
|
value.format = vpiVectorVal;
|
|
|
|
|
value.value.vector = res;
|
|
|
|
|
|
|
|
|
|
/* return converted value */
|
2008-01-07 04:50:59 +01:00
|
|
|
vpi_put_value(callh, &value, 0, vpiNoDelay);
|
2003-03-17 22:59:54 +01:00
|
|
|
|
2003-03-07 03:44:33 +01:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2010-10-04 18:31:01 +02:00
|
|
|
static PLI_INT32 sys_rtoi_calltf(ICARUS_VPI_CONST PLI_BYTE8*user)
|
2003-03-11 00:40:10 +01:00
|
|
|
{
|
2008-01-07 04:50:59 +01:00
|
|
|
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
|
|
|
|
vpiHandle arg = (vpiHandle) vpi_get_userdata(callh);
|
2003-03-11 00:40:10 +01:00
|
|
|
s_vpi_value value;
|
|
|
|
|
static struct t_vpi_vecval res;
|
2013-10-11 19:48:01 +02:00
|
|
|
double val;
|
2003-03-11 00:40:10 +01:00
|
|
|
|
|
|
|
|
/* get value */
|
|
|
|
|
value.format = vpiRealVal;
|
|
|
|
|
vpi_get_value(arg, &value);
|
|
|
|
|
|
2013-10-11 19:48:01 +02:00
|
|
|
/* If the value is NaN or +/- infinity then return 'bx */
|
|
|
|
|
val = value.value.real;
|
|
|
|
|
if (val != val || (val && (val == 0.5*val))) {
|
|
|
|
|
res.aval = ~(PLI_INT32)0;
|
|
|
|
|
res.bval = ~(PLI_INT32)0;
|
|
|
|
|
} else {
|
2013-10-12 02:29:56 +02:00
|
|
|
/* This is not 100% correct since large real values may break this
|
|
|
|
|
* code. See the verinum code for a more rigorous implementation. */
|
|
|
|
|
if (val >= 0.0) res.aval = (PLI_UINT64) val;
|
|
|
|
|
else res.aval = - (PLI_UINT64) -val;
|
2013-10-11 19:48:01 +02:00
|
|
|
res.bval = 0;
|
|
|
|
|
}
|
2003-03-11 00:40:10 +01:00
|
|
|
|
|
|
|
|
value.format = vpiVectorVal;
|
|
|
|
|
value.value.vector = &res;
|
|
|
|
|
|
|
|
|
|
/* return converted value */
|
2008-01-07 04:50:59 +01:00
|
|
|
vpi_put_value(callh, &value, 0, vpiNoDelay);
|
2003-03-17 22:59:54 +01:00
|
|
|
|
2003-03-11 00:40:10 +01:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2003-03-07 03:44:33 +01:00
|
|
|
void sys_convert_register()
|
|
|
|
|
{
|
|
|
|
|
s_vpi_systf_data tf_data;
|
2010-04-12 08:39:08 +02:00
|
|
|
vpiHandle res;
|
2003-03-11 00:40:10 +01:00
|
|
|
|
2003-03-07 03:44:33 +01:00
|
|
|
tf_data.type = vpiSysFunc;
|
2004-02-15 19:03:30 +01:00
|
|
|
tf_data.user_data = "$bitstoreal";
|
|
|
|
|
tf_data.tfname = tf_data.user_data;
|
2003-03-07 03:44:33 +01:00
|
|
|
tf_data.sizetf = sizetf_64;
|
2003-03-11 00:40:10 +01:00
|
|
|
tf_data.compiletf = sys_convert_compiletf;
|
2003-03-17 22:59:54 +01:00
|
|
|
tf_data.calltf = sys_bitstoreal_calltf;
|
2010-04-12 08:39:08 +02:00
|
|
|
res = vpi_register_systf(&tf_data);
|
|
|
|
|
vpip_make_systf_system_defined(res);
|
2003-03-07 03:44:33 +01:00
|
|
|
|
|
|
|
|
tf_data.type = vpiSysFunc;
|
2004-02-15 19:03:30 +01:00
|
|
|
tf_data.user_data = "$itor";
|
|
|
|
|
tf_data.tfname = tf_data.user_data;
|
2003-03-07 03:44:33 +01:00
|
|
|
tf_data.sizetf = sizetf_64;
|
2003-03-11 00:40:10 +01:00
|
|
|
tf_data.compiletf = sys_convert_compiletf;
|
2003-03-17 22:59:54 +01:00
|
|
|
tf_data.calltf = sys_itor_calltf;
|
2010-04-12 08:39:08 +02:00
|
|
|
res = vpi_register_systf(&tf_data);
|
|
|
|
|
vpip_make_systf_system_defined(res);
|
2003-03-07 03:44:33 +01:00
|
|
|
|
|
|
|
|
tf_data.type = vpiSysFunc;
|
2004-02-15 19:03:30 +01:00
|
|
|
tf_data.user_data = "$realtobits";
|
|
|
|
|
tf_data.tfname = tf_data.user_data;
|
2003-03-07 03:44:33 +01:00
|
|
|
tf_data.sizetf = sizetf_64;
|
2003-03-11 00:40:10 +01:00
|
|
|
tf_data.compiletf = sys_convert_compiletf;
|
|
|
|
|
tf_data.calltf = sys_realtobits_calltf;
|
2010-04-12 08:39:08 +02:00
|
|
|
res = vpi_register_systf(&tf_data);
|
|
|
|
|
vpip_make_systf_system_defined(res);
|
2003-03-07 03:44:33 +01:00
|
|
|
|
|
|
|
|
tf_data.type = vpiSysFunc;
|
2004-02-15 19:03:30 +01:00
|
|
|
tf_data.user_data = "$rtoi";
|
|
|
|
|
tf_data.tfname = tf_data.user_data;
|
2003-03-07 03:44:33 +01:00
|
|
|
tf_data.sizetf = sizetf_32;
|
2003-03-11 00:40:10 +01:00
|
|
|
tf_data.compiletf = sys_convert_compiletf;
|
|
|
|
|
tf_data.calltf = sys_rtoi_calltf;
|
2010-04-12 08:39:08 +02:00
|
|
|
res = vpi_register_systf(&tf_data);
|
|
|
|
|
vpip_make_systf_system_defined(res);
|
2003-03-07 03:44:33 +01:00
|
|
|
}
|
|
|
|
|
|