From b14c4ca26c4092e78447cbaec46c0b96cc724b11 Mon Sep 17 00:00:00 2001 From: Cary R Date: Thu, 28 Dec 2023 13:29:07 -0800 Subject: [PATCH] add suport for the shortreal conversion functions --- ivtest/ivltests/br_gh1018.v | 40 ++++++++ ivtest/regress-vvp.list | 5 +- ivtest/vvp_tests/br_gh1018.json | 5 + vpi/sys_convert.c | 165 ++++++++++++++++++++++++++++---- 4 files changed, 195 insertions(+), 20 deletions(-) create mode 100644 ivtest/ivltests/br_gh1018.v create mode 100644 ivtest/vvp_tests/br_gh1018.json diff --git a/ivtest/ivltests/br_gh1018.v b/ivtest/ivltests/br_gh1018.v new file mode 100644 index 000000000..042be6562 --- /dev/null +++ b/ivtest/ivltests/br_gh1018.v @@ -0,0 +1,40 @@ +module top; + // Test the shortreal conversion functions, but we don't support shortreal + // as a type yet so be safe with the actual values that are checked to + // avoid any real (double) to shortreal (float) rounding. + real in; + reg [31:0] irep; + real res; + reg passed; + + initial begin + passed = 1'b1; + + in = 0.0; + irep = $shortrealtobits(in); + res = $bitstoshortreal(irep); + if (in != res) begin + $display("Input and output value do not match (%f != %f)", in, res); + passed = 1'b0; + end + + in = 8.0; + irep = $shortrealtobits(in); + res = $bitstoshortreal(irep); + if (in != res) begin + $display("Input and output value do not match (%f != %f)", in, res); + passed = 1'b0; + end + + + in = 0.125; + irep = $shortrealtobits(in); + res = $bitstoshortreal(irep); + if (in != res) begin + $display("Input and output value do not match (%f != %f)", in, res); + passed = 1'b0; + end + + if (passed) $display("PASSED"); + end +endmodule diff --git a/ivtest/regress-vvp.list b/ivtest/regress-vvp.list index 09091b4e2..8aeca1fcb 100644 --- a/ivtest/regress-vvp.list +++ b/ivtest/regress-vvp.list @@ -14,6 +14,8 @@ bits4 vvp_tests/bits4.json bitsel11 vvp_tests/bitsel11.json br_gh13a vvp_tests/br_gh13a.json br_gh13a-vlog95 vvp_tests/br_gh13a-vlog95.json +br_gh99c vvp_tests/br_gh99c.json +br_gh99c-vlog95 vvp_tests/br_gh99c-vlog95.json br_gh230 vvp_tests/br_gh230.json br_gh383a vvp_tests/br_gh383a.json br_gh383b vvp_tests/br_gh383b.json @@ -21,8 +23,7 @@ br_gh383c vvp_tests/br_gh383c.json br_gh383d vvp_tests/br_gh383d.json br_gh440 vvp_tests/br_gh440.json br_gh939 vvp_tests/br_gh939.json -br_gh99c vvp_tests/br_gh99c.json -br_gh99c-vlog95 vvp_tests/br_gh99c-vlog95.json +br_gh1018 vvp_tests/br_gh1018.json ca_time_real` vvp_tests/ca_time_real.json case1 vvp_tests/case1.json case2 vvp_tests/case2.json diff --git a/ivtest/vvp_tests/br_gh1018.json b/ivtest/vvp_tests/br_gh1018.json new file mode 100644 index 000000000..41c179a8a --- /dev/null +++ b/ivtest/vvp_tests/br_gh1018.json @@ -0,0 +1,5 @@ +{ + "type" : "normal", + "source" : "br_gh1018.v", + "iverilog-args" : [ "-g2005-sv" ] +} diff --git a/vpi/sys_convert.c b/vpi/sys_convert.c index bf46615fd..cf83dfaa7 100644 --- a/vpi/sys_convert.c +++ b/vpi/sys_convert.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2021 Michael Ruff (mruff at chiaro.com) + * Copyright (c) 2003-2023 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 @@ -62,23 +62,67 @@ static void double2bits(double real, PLI_UINT32 bits[2]) 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); + 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] - | (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); + 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 } @@ -97,6 +141,12 @@ static PLI_INT32 sizetf_64 (ICARUS_VPI_CONST PLI_BYTE8*name) 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); @@ -112,11 +162,15 @@ static PLI_INT32 sys_convert_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name) /* In Icarus if we have an argv we have at least one argument. */ arg = vpi_scan(argv); - /* Validate the argument. Only $bitstoreal for now. */ + /* 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); @@ -153,6 +207,31 @@ static PLI_INT32 sys_bitstoreal_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) 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); @@ -207,6 +286,36 @@ static PLI_INT32 sys_realtobits_calltf(ICARUS_VPI_CONST PLI_BYTE8*name) 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); @@ -258,6 +367,16 @@ void sys_convert_register(void) 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"; @@ -278,6 +397,16 @@ void sys_convert_register(void) 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";