From 40558160e7e4217eca3fcdf60fa357391e5f2700 Mon Sep 17 00:00:00 2001 From: Cary R Date: Thu, 30 Aug 2018 22:29:22 -0700 Subject: [PATCH] Add support for bit vector system function in vpi --- netlist.cc | 2 +- vpi/Makefile.in | 3 +- vpi/sys_bit_vec.c | 340 ++++++++++++++++++++++++++++++++++++++++++++++ vpi/sys_priv.c | 22 ++- vpi/sys_priv.h | 8 +- vpi/sys_table.c | 4 +- vpi/system.sft | 6 + 7 files changed, 380 insertions(+), 5 deletions(-) create mode 100644 vpi/sys_bit_vec.c diff --git a/netlist.cc b/netlist.cc index 803316a2a..c0650959e 100644 --- a/netlist.cc +++ b/netlist.cc @@ -2954,7 +2954,7 @@ static bool do_expr_event_match(const NetExpr*expr, const NetEvWait*evwt) // The event wait should only have a single event. if (evwt->nevents() != 1) return false; // The event should have a single probe. - const NetEvent* evt = evwt->event(0); + const NetEvent *evt = evwt->event(0); if (evt->nprobe() != 1) return false; // The probe should be for any edge. const NetEvProbe *prb = evt->probe(0); diff --git a/vpi/Makefile.in b/vpi/Makefile.in index aebdb70b2..366683ac8 100644 --- a/vpi/Makefile.in +++ b/vpi/Makefile.in @@ -51,7 +51,8 @@ CXXFLAGS = @WARNING_FLAGS@ @WARNING_FLAGS_CXX@ @CXXFLAGS@ LDFLAGS = @LDFLAGS@ # Object files for system.vpi -O = sys_table.o sys_convert.o sys_countdrivers.o sys_darray.o sys_deposit.o sys_display.o \ +O = sys_table.o sys_bit_vec.o sys_convert.o sys_countdrivers.o sys_darray.o \ + sys_deposit.o sys_display.o \ sys_fileio.o sys_finish.o sys_icarus.o sys_plusargs.o sys_queue.o \ sys_random.o sys_random_mti.o sys_readmem.o sys_readmem_lex.o sys_scanf.o \ sys_sdf.o sys_time.o sys_vcd.o sys_vcdoff.o vcd_priv.o mt19937int.o \ diff --git a/vpi/sys_bit_vec.c b/vpi/sys_bit_vec.c new file mode 100644 index 000000000..074f2f221 --- /dev/null +++ b/vpi/sys_bit_vec.c @@ -0,0 +1,340 @@ +/* + * Copyright (C) 2018 Cary R. (cygcary@yahoo.com) + * + * This program is free software; you can redistribute it and/or modify + * it 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 +#include "vpi_user.h" +#include "sys_priv.h" + +/* + * Check that $couintbits() is called with the correct arguments. + */ +static PLI_INT32 sys_countbits_compiletf(ICARUS_VPI_CONST PLI_BYTE8 *name) +{ + vpiHandle callh = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv, arg; + int cb_count = 1; + + assert(callh != 0); + argv = vpi_iterate(vpiArgument, callh); + (void)name; /* Parameter is not used. */ + + /* $countbits() must have arguments. */ + if (argv == 0) { + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("$countbits() requires at least two arguments.\n"); + vpi_control(vpiFinish, 1); + return 0; + } + + /* The 1st argument must be numeric. */ + arg = vpi_scan(argv); + if (! is_numeric_obj(arg)) { + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("The first argument to $countbits() must be numeric.\n"); + vpi_control(vpiFinish, 1); + } + + /* We need one or more numeric control bit arguments. */ + arg = vpi_scan(argv); + if (! arg) { + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("$countbits() requires at least one control bit " + "argument.\n"); + vpi_control(vpiFinish, 1); + } + + do { + if (arg && ! is_numeric_obj(arg)) { + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("Control bit argument %d to $countbits() must " + "be numeric.\n", cb_count); + vpi_control(vpiFinish, 1); + } + ++cb_count; + if (arg) arg = vpi_scan(argv); + } while (arg); + + return 0; +} + +/* Count the number of bits in the expression that match the search bits. */ +static PLI_INT32 count_bits_in_expr(vpiHandle expr_arg, char search[4]) +{ + s_vpi_value val; + PLI_INT32 result; + PLI_INT32 size = vpi_get(vpiSize, expr_arg); + assert(size > 0); + + val.format = vpiVectorVal; + vpi_get_value(expr_arg, &val); + + result = 0; + for (unsigned lp = 0; lp < (unsigned)size; ++lp) { + unsigned offset = lp / 32; + unsigned bit = lp % 32; + unsigned abit, bbit; + abit = (val.value.vector[offset].aval >> bit) & 0x1; + bbit = (val.value.vector[offset].bval >> bit) & 0x1; + if (search[(bbit<<1)|abit]) ++result; + } + + return result; +} + +static PLI_INT32 sys_countbits_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name) +{ + vpiHandle callh = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv = vpi_iterate(vpiArgument, callh); + vpiHandle expr_arg = vpi_scan(argv); + vpiHandle arg; + char search[4]; + (void)name; /* Parameter is not used. */ + + /* Scan the control bit arguments and mark which control bits to + * include in the count. */ + for (unsigned lp = 0; lp < 4 ; ++lp) search[lp] = 0; + while ((arg = vpi_scan(argv))) { + s_vpi_value val; + val.format = vpiScalarVal; + vpi_get_value(arg, &val); + switch (val.value.scalar) { + case vpi0: + search[0] = 1; + break; + case vpi1: + search[1] = 1; + break; + case vpiZ: + search[2] = 1; + break; + case vpiX: + search[3] = 1; + break; + default: + vpi_printf("WARNING: %s:%d: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("Unknown scalar control bit argument %d passed " + "to $countbits() will be ignored.\n", + val.value.scalar); + break; + } + } + + put_integer_value(callh, count_bits_in_expr(expr_arg, search)); + + return 0; +} + +/* Count the number of ones in the expression. */ +static PLI_INT32 count_ones_in_expr(vpiHandle expr_arg) +{ + s_vpi_value val; + PLI_INT32 result; + PLI_INT32 size = vpi_get(vpiSize, expr_arg); + assert(size > 0); + + val.format = vpiVectorVal; + vpi_get_value(expr_arg, &val); + + result = 0; + size = (size + 31) / 32; + for (unsigned lp = 0; lp < (unsigned)size; ++lp) { + PLI_UINT32 ones = ~val.value.vector[lp].bval & + val.value.vector[lp].aval; + while (ones) { + if (ones & 0x1) ++result; + ones >>= 1; + } + } + + return result; +} + +static PLI_INT32 sys_countones_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name) +{ + vpiHandle callh = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv = vpi_iterate(vpiArgument, callh); + vpiHandle expr_arg = vpi_scan(argv); + (void)name; /* Parameter is not used. */ + + vpi_free_object(argv); + + put_integer_value(callh, count_ones_in_expr(expr_arg)); + + return 0; +} + +/* Check to see if the expression is onehot. */ +static PLI_INT32 is_onehot(vpiHandle expr_arg, unsigned zero_is_okay) +{ + s_vpi_value val; + unsigned found_a_one; + PLI_INT32 size = vpi_get(vpiSize, expr_arg); + assert(size > 0); + + val.format = vpiVectorVal; + vpi_get_value(expr_arg, &val); + + found_a_one = 0; + size = (size + 31) / 32; + for (unsigned lp = 0; lp < (unsigned)size; ++lp) { + PLI_UINT32 ones = ~val.value.vector[lp].bval & + val.value.vector[lp].aval; + while (ones) { + if (ones & 0x1) { + if (found_a_one) return vpi0; + found_a_one = 1; + } + ones >>= 1; + } + } + + if (found_a_one) return vpi1; + else if (zero_is_okay) return vpi1; + return vpi0; +} + +static PLI_INT32 sys_onehot_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name) +{ + vpiHandle callh = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv = vpi_iterate(vpiArgument, callh); + vpiHandle expr_arg = vpi_scan(argv); + (void)name; /* Parameter is not used. */ + + vpi_free_object(argv); + + put_scalar_value(callh, is_onehot(expr_arg, 0)); + + return 0; +} + +static PLI_INT32 sys_onehot0_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name) +{ + vpiHandle callh = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv = vpi_iterate(vpiArgument, callh); + vpiHandle expr_arg = vpi_scan(argv); + (void)name; /* Parameter is not used. */ + + vpi_free_object(argv); + + put_scalar_value(callh, is_onehot(expr_arg, 1)); + + return 0; +} + +/* Check to see if the expression has an undefined value. */ +static PLI_INT32 is_unknown(vpiHandle expr_arg) +{ + s_vpi_value val; + PLI_INT32 size = vpi_get(vpiSize, expr_arg); + assert(size > 0); + + val.format = vpiVectorVal; + vpi_get_value(expr_arg, &val); + + size = (size + 31) / 32; + for (unsigned lp = 0; lp < (unsigned)size; ++lp) { + if (val.value.vector[lp].bval) return vpi1; + } + + return vpi0; +} + +static PLI_INT32 sys_isunknown_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name) +{ + vpiHandle callh = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv = vpi_iterate(vpiArgument, callh); + vpiHandle expr_arg = vpi_scan(argv); + (void)name; /* Parameter is not used. */ + + vpi_free_object(argv); + + put_scalar_value(callh, is_unknown(expr_arg)); + + return 0; +} + +static PLI_INT32 sys_bit_vec_sizetf(ICARUS_VPI_CONST PLI_BYTE8 *name) +{ + (void)name; /* Parameter is not used. */ + + return 1; +} + +/* + * Register the functions with Verilog. + */ +void sys_bit_vec_register(void) +{ + s_vpi_systf_data tf_data; + vpiHandle res; + + tf_data.type = vpiSysFunc; + tf_data.sysfunctype = vpiIntFunc; + tf_data.calltf = sys_countbits_calltf; + tf_data.compiletf = sys_countbits_compiletf; + tf_data.sizetf = 0; + tf_data.tfname = "$countbits"; + tf_data.user_data = 0; + res = vpi_register_systf(&tf_data); + vpip_make_systf_system_defined(res); + + tf_data.type = vpiSysFunc; + tf_data.sysfunctype = vpiIntFunc; + tf_data.calltf = sys_countones_calltf; + tf_data.compiletf = sys_one_numeric_arg_compiletf; + tf_data.sizetf = 0; + tf_data.tfname = "$countones"; + tf_data.user_data = "$countones"; + res = vpi_register_systf(&tf_data); + vpip_make_systf_system_defined(res); + + tf_data.type = vpiSysFunc; + tf_data.sysfunctype = vpiSizedFunc; + tf_data.calltf = sys_onehot_calltf; + tf_data.compiletf = sys_one_numeric_arg_compiletf; + tf_data.sizetf = sys_bit_vec_sizetf; + tf_data.tfname = "$onehot"; + tf_data.user_data = "$onehot"; + res = vpi_register_systf(&tf_data); + vpip_make_systf_system_defined(res); + + tf_data.type = vpiSysFunc; + tf_data.sysfunctype = vpiSizedFunc; + tf_data.calltf = sys_onehot0_calltf; + tf_data.compiletf = sys_one_numeric_arg_compiletf; + tf_data.sizetf = sys_bit_vec_sizetf; + tf_data.tfname = "$onehot0"; + tf_data.user_data = "$onehot0"; + res = vpi_register_systf(&tf_data); + vpip_make_systf_system_defined(res); + + tf_data.type = vpiSysFunc; + tf_data.sysfunctype = vpiSizedFunc; + tf_data.calltf = sys_isunknown_calltf; + tf_data.compiletf = sys_one_numeric_arg_compiletf; + tf_data.sizetf = sys_bit_vec_sizetf; + tf_data.tfname = "$isunknown"; + tf_data.user_data = "$isunknown"; + res = vpi_register_systf(&tf_data); + vpip_make_systf_system_defined(res); +} diff --git a/vpi/sys_priv.c b/vpi/sys_priv.c index b8f333ebe..dd9714325 100644 --- a/vpi/sys_priv.c +++ b/vpi/sys_priv.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2017 Stephen Williams (steve@icarus.com) + * Copyright (c) 2003-2018 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 @@ -399,3 +399,23 @@ PLI_INT32 sys_one_string_arg_compiletf(ICARUS_VPI_CONST PLI_BYTE8 *name) return 0; } + +/* Return an integer value to the caller. */ +void put_integer_value(vpiHandle callh, PLI_INT32 result) +{ + s_vpi_value val; + + val.format = vpiIntVal; + val.value.integer = result; + vpi_put_value(callh, &val, 0, vpiNoDelay); +} + +/* Return a scalar value to the caller. */ +void put_scalar_value(vpiHandle callh, PLI_INT32 result) +{ + s_vpi_value val; + + val.format = vpiScalarVal; + val.value.scalar = result; + vpi_put_value(callh, &val, 0, vpiNoDelay); +} diff --git a/vpi/sys_priv.h b/vpi/sys_priv.h index 36553b250..d9052d51d 100644 --- a/vpi/sys_priv.h +++ b/vpi/sys_priv.h @@ -1,7 +1,7 @@ #ifndef IVL_sys_priv_H #define IVL_sys_priv_H /* - * Copyright (c) 2002-2014 Stephen Williams (steve@icarus.com) + * Copyright (c) 2002-2018 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 @@ -65,4 +65,10 @@ extern PLI_INT32 sys_one_opt_numeric_arg_compiletf(ICARUS_VPI_CONST PLI_BYTE8 *n extern PLI_INT32 sys_two_numeric_args_compiletf(ICARUS_VPI_CONST PLI_BYTE8 *name); extern PLI_INT32 sys_one_string_arg_compiletf(ICARUS_VPI_CONST PLI_BYTE8 *name); +/* + * The standard put/return a value to the caller routines. + */ +extern void put_integer_value(vpiHandle callh, PLI_INT32 result); +extern void put_scalar_value(vpiHandle callh, PLI_INT32 result); + #endif /* IVL_sys_priv_H */ diff --git a/vpi/sys_table.c b/vpi/sys_table.c index bb5e3ad7e..a78754534 100644 --- a/vpi/sys_table.c +++ b/vpi/sys_table.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2010,2012 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2018 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 @@ -23,6 +23,7 @@ # include # include +extern void sys_bit_vec_register(void); extern void sys_convert_register(void); extern void sys_countdrivers_register(void); extern void sys_darray_register(void); @@ -196,6 +197,7 @@ static void sys_lxt_or_vcd_register(void) } void (*vlog_startup_routines[])(void) = { + sys_bit_vec_register, sys_convert_register, sys_countdrivers_register, sys_darray_register, diff --git a/vpi/system.sft b/vpi/system.sft index be082c85f..93e67cfd2 100644 --- a/vpi/system.sft +++ b/vpi/system.sft @@ -17,6 +17,12 @@ $dist_erlang vpiSysFuncInt $clog2 vpiSysFuncInt $q_full vpiSysFuncInt +$countbits vpiSysFuncInt +$countones vpiSysFuncInt +$onehot vpiSysFuncSized 1 unsigned +$onehot0 vpiSysFuncSized 1 unsigned +$isunknown vpiSysFuncSized 1 unsigned + $abstime vpiSysFuncReal $simparam vpiSysFuncReal $simparam$str vpiSysFuncSized 1024 unsigned