/* * Copyright (c) 2003-2025 Michael Ruff (mruff at chiaro.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ # include "sys_priv.h" # include # include # include static double bits2double(PLI_UINT32 const 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; } 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] << 0) | (conv.bval[6] << 8) | (conv.bval[5] << 16) | (conv.bval[4] << 24); bits[1] = (conv.bval[3] << 0) | (conv.bval[2] << 8) | (conv.bval[1] << 16) | (conv.bval[0] << 24); #else bits[0] = (conv.bval[0] << 0) | (conv.bval[1] << 8) | (conv.bval[2] << 16) | (conv.bval[3] << 24); bits[1] = (conv.bval[4] << 0) | (conv.bval[5] << 8) | (conv.bval[6] << 16) | (conv.bval[7] << 24); #endif } static float bits2float(PLI_UINT32 bits) { union conv { float rval; unsigned char bval[sizeof(float)]; } conv; #ifdef WORDS_BIGENDIAN conv.bval[3] = (bits >> 0) & 0xff; conv.bval[2] = (bits >> 8) & 0xff; conv.bval[1] = (bits >> 16) & 0xff; conv.bval[0] = (bits >> 24) & 0xff; #else conv.bval[0] = (bits >> 0) & 0xff; conv.bval[1] = (bits >> 8) & 0xff; conv.bval[2] = (bits >> 16) & 0xff; conv.bval[3] = (bits >> 24) & 0xff; #endif return conv.rval; } static void float2bits(float real, PLI_UINT32*bits) { union conv { float rval; unsigned char bval[sizeof(float)]; } conv; conv.rval = real; #ifdef WORDS_BIGENDIAN *bits = (conv.bval[3] << 0) | (conv.bval[2] << 8) | (conv.bval[1] << 16) | (conv.bval[0] << 24); #else *bits = (conv.bval[0] << 0) | (conv.bval[1] << 8) | (conv.bval[2] << 16) | (conv.bval[3] << 24); #endif } static void error_message(vpiHandle callh, const char* msg) { vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), (int)vpi_get(vpiLineNo, callh)); vpi_printf(msg, vpi_get_str(vpiName, callh)); vpip_set_return_value(1); vpi_control(vpiFinish, 1); } static PLI_INT32 sizetf_64 (ICARUS_VPI_CONST PLI_BYTE8*name) { (void)name; /* Parameter is not used. */ return 64; } static PLI_INT32 sizetf_32 (ICARUS_VPI_CONST PLI_BYTE8*name) { (void)name; /* Parameter is not used. */ return 32; } static PLI_INT32 sys_convert_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name) { 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; } /* In Icarus if we have an argv we have at least one argument. */ arg = vpi_scan(argv); /* Validate the argument. Only $bitstoreal and $bitstoshortreal for now. */ if (!strcmp("$bitstoreal", name) && vpi_get(vpiSize, arg) != 64) { error_message(callh, "%s requires a 64-bit argument.\n"); return 0; } if (!strcmp("$bitstoshortreal", name) && vpi_get(vpiSize, arg) != 32) { error_message(callh, "%s requires a 32-bit argument.\n"); return 0; } /* Save the argument away to make the calltf faster. */ vpi_put_userdata(callh, (void *) arg); /* These functions only take one argument. */ check_for_extra_args(argv, callh, name, "one argument", 0); return 0; } static PLI_INT32 sys_bitstoreal_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) { vpiHandle callh = vpi_handle(vpiSysTfCall, 0); vpiHandle arg = (vpiHandle) vpi_get_userdata(callh); s_vpi_value value; PLI_UINT32 bits[2]; (void)name; /* Parameter is not used. */ /* 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 */ vpi_put_value(callh, &value, 0, vpiNoDelay); return 0; } static PLI_INT32 sys_bitstoshortreal_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) { vpiHandle callh = vpi_handle(vpiSysTfCall, 0); vpiHandle arg = (vpiHandle) vpi_get_userdata(callh); s_vpi_value value; PLI_UINT32 bits; (void)name; /* Parameter is not used. */ /* get value */ value.format = vpiVectorVal; vpi_get_value(arg, &value); /* convert */ bits = (value.value.vector[0]).aval; value.value.real = bits2float(bits); value.format = vpiRealVal; /* return converted value */ vpi_put_value(callh, &value, 0, vpiNoDelay); return 0; } static PLI_INT32 sys_itor_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) { vpiHandle callh = vpi_handle(vpiSysTfCall, 0); vpiHandle arg = (vpiHandle) vpi_get_userdata(callh); s_vpi_value value; (void)name; /* Parameter is not used. */ /* get value */ value.format = vpiIntVal; vpi_get_value(arg, &value); /* convert */ value.value.real = value.value.integer; value.format = vpiRealVal; /* return converted value */ vpi_put_value(callh, &value, 0, vpiNoDelay); return 0; } static PLI_INT32 sys_realtobits_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) { vpiHandle callh = vpi_handle(vpiSysTfCall, 0); vpiHandle arg = (vpiHandle) vpi_get_userdata(callh); s_vpi_value value; static struct t_vpi_vecval res[2]; PLI_UINT32 bits[2]; (void)name; /* Parameter is not used. */ /* get value */ value.format = vpiRealVal; vpi_get_value(arg, &value); /* convert */ 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 */ vpi_put_value(callh, &value, 0, vpiNoDelay); return 0; } static PLI_INT32 sys_shortrealtobits_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) { vpiHandle callh = vpi_handle(vpiSysTfCall, 0); vpiHandle arg = (vpiHandle) vpi_get_userdata(callh); s_vpi_value value; static struct t_vpi_vecval res[1]; PLI_UINT32 bits; (void)name; /* Parameter is not used. */ /* get value */ value.format = vpiRealVal; vpi_get_value(arg, &value); /* convert */ float2bits(value.value.real, &bits); res[0].aval = bits; res[0].bval = 0; value.format = vpiVectorVal; value.value.vector = res; /* return converted value */ vpi_put_value(callh, &value, 0, vpiNoDelay); return 0; } static PLI_INT32 sys_rtoi_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) { vpiHandle callh = vpi_handle(vpiSysTfCall, 0); vpiHandle arg = (vpiHandle) vpi_get_userdata(callh); s_vpi_value value; static struct t_vpi_vecval res; double val; (void)name; /* Parameter is not used. */ /* get value */ value.format = vpiRealVal; vpi_get_value(arg, &value); /* 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 { /* 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; res.bval = 0; } value.format = vpiVectorVal; value.value.vector = &res; /* return converted value */ vpi_put_value(callh, &value, 0, vpiNoDelay); return 0; } void sys_convert_register(void) { s_vpi_systf_data tf_data; vpiHandle res; tf_data.type = vpiSysFunc; tf_data.sysfunctype = vpiRealFunc; tf_data.user_data = "$bitstoreal"; tf_data.tfname = tf_data.user_data; tf_data.sizetf = 0; tf_data.compiletf = sys_convert_compiletf; tf_data.calltf = sys_bitstoreal_calltf; res = vpi_register_systf(&tf_data); vpip_make_systf_system_defined(res); tf_data.type = vpiSysFunc; tf_data.sysfunctype = vpiRealFunc; tf_data.user_data = "$bitstoshortreal"; tf_data.tfname = tf_data.user_data; tf_data.sizetf = 0; tf_data.compiletf = sys_convert_compiletf; tf_data.calltf = sys_bitstoshortreal_calltf; res = vpi_register_systf(&tf_data); vpip_make_systf_system_defined(res); tf_data.type = vpiSysFunc; tf_data.sysfunctype = vpiRealFunc; tf_data.user_data = "$itor"; tf_data.tfname = tf_data.user_data; tf_data.sizetf = 0; tf_data.compiletf = sys_convert_compiletf; tf_data.calltf = sys_itor_calltf; res = vpi_register_systf(&tf_data); vpip_make_systf_system_defined(res); tf_data.type = vpiSysFunc; tf_data.sysfunctype = vpiSizedFunc; tf_data.user_data = "$realtobits"; tf_data.tfname = tf_data.user_data; tf_data.sizetf = sizetf_64; tf_data.compiletf = sys_convert_compiletf; tf_data.calltf = sys_realtobits_calltf; res = vpi_register_systf(&tf_data); vpip_make_systf_system_defined(res); tf_data.type = vpiSysFunc; tf_data.sysfunctype = vpiSizedFunc; tf_data.user_data = "$shortrealtobits"; tf_data.tfname = tf_data.user_data; tf_data.sizetf = sizetf_32; tf_data.compiletf = sys_convert_compiletf; tf_data.calltf = sys_shortrealtobits_calltf; res = vpi_register_systf(&tf_data); vpip_make_systf_system_defined(res); tf_data.type = vpiSysFunc; tf_data.sysfunctype = vpiIntFunc; tf_data.user_data = "$rtoi"; tf_data.tfname = tf_data.user_data; tf_data.sizetf = 0; tf_data.compiletf = sys_convert_compiletf; tf_data.calltf = sys_rtoi_calltf; res = vpi_register_systf(&tf_data); vpip_make_systf_system_defined(res); }