diff --git a/vpi/Makefile.in b/vpi/Makefile.in index a0aa48993..fbe12f2c4 100644 --- a/vpi/Makefile.in +++ b/vpi/Makefile.in @@ -52,11 +52,11 @@ CXXFLAGS = @WARNING_FLAGS@ @WARNING_FLAGS_CXX@ @CXXFLAGS@ LDFLAGS = @LDFLAGS@ # Object files for system.vpi -O = sys_table.o sys_convert.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 sys_priv.o \ - sdf_lexor.o sdf_parse.o stringheap.o vams_simparam.o \ +O = sys_table.o sys_convert.o sys_countdrivers.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 \ + sys_priv.o sdf_lexor.o sdf_parse.o stringheap.o vams_simparam.o \ table_mod.o table_mod_lexor.o table_mod_parse.o OPP = vcd_priv2.o diff --git a/vpi/sys_countdrivers.c b/vpi/sys_countdrivers.c new file mode 100644 index 000000000..304672ec8 --- /dev/null +++ b/vpi/sys_countdrivers.c @@ -0,0 +1,212 @@ +/* + * Copyright (C) 2012 Martin Whitaker. (icarus@martin-whitaker.me.uk) + * + * 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 "sys_priv.h" +#include +#include +#include +#include "ivl_alloc.h" + +/* + * Check to see if an argument is a single bit net. + */ +static void check_net_arg(vpiHandle arg, vpiHandle callh, const char *name) +{ + assert(arg); + + switch (vpi_get(vpiType, arg)) { + case vpiPartSelect: + if (vpi_get(vpiType, vpi_handle(vpiParent, arg)) != vpiNet) + break; + case vpiNet: + if (vpi_get(vpiSize, arg) != 1) + break; + return; + default: + break; + } + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s's first argument must be a scalar net or " + "a bit-select of a vector net.\n", name); + vpi_control(vpiFinish, 1); +} + +/* + * Check to see if an argument is a variable. + */ +static void check_var_arg(vpiHandle arg, vpiHandle callh, const char *name, + const char *arg_name) +{ + assert(arg); + + switch (vpi_get(vpiType, arg)) { + case vpiPartSelect: + if (vpi_get(vpiType, vpi_handle(vpiParent, arg)) == vpiNet) + break; + case vpiMemoryWord: + case vpiBitVar: + case vpiReg: + case vpiIntegerVar: + case vpiIntVar: + case vpiLongIntVar: + case vpiTimeVar: + return; + default: + break; + } + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s's %s argument must be a variable.\n", + name, arg_name); + vpi_control(vpiFinish, 1); +} + +/* + * Check that the given $countdrivers() call has valid arguments. + */ +static PLI_INT32 sys_countdrivers_compiletf(ICARUS_VPI_CONST PLI_BYTE8 *name) +{ + vpiHandle callh = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv = vpi_iterate(vpiArgument, callh); + vpiHandle arg; + unsigned arg_num; + + /* Check that there are arguments. */ + if (argv == 0) { + vpi_printf("ERROR: %s:%d: ", vpi_get_str(vpiFile, callh), + (int)vpi_get(vpiLineNo, callh)); + vpi_printf("%s requires at least one argument.\n", name); + vpi_control(vpiFinish, 1); + return 0; + } + + /* The first argument must be a scalar net or a net bit select. */ + arg = vpi_scan(argv); + check_net_arg(arg, callh, name); + + /* The optional arguments must be variables. */ + for (arg_num = 2; arg_num < 7; arg_num += 1) { + char *arg_name = NULL; + switch (arg_num) { + case 2: arg_name = "second"; break; + case 3: arg_name = "third"; break; + case 4: arg_name = "fourth"; break; + case 5: arg_name = "fifth"; break; + case 6: arg_name = "sixth"; break; + default: assert(0); + } + + arg = vpi_scan(argv); + if (arg == 0) + return 0; + + check_var_arg(arg, callh, name, arg_name); + } + + /* Make sure there are no extra arguments. */ + check_for_extra_args(argv, callh, name, "six arguments", 0); + return 0; +} + +/* + * The runtime code for $countdrivers(). + */ +static PLI_INT32 sys_countdrivers_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name) +{ + vpiHandle callh = vpi_handle(vpiSysTfCall, 0); + vpiHandle argv = vpi_iterate(vpiArgument, callh); + vpiHandle arg; + unsigned idx; + unsigned counts[4]; + unsigned num_drivers; + s_vpi_value val; + + /* All returned values are integers. */ + val.format = vpiIntVal; + + /* Get the base net reference and bit select */ + idx = 0; + arg = vpi_scan(argv); + assert(arg); + if (vpi_get(vpiType, arg) == vpiPartSelect) { + idx = vpi_get(vpiLeftRange, arg); + arg = vpi_handle(vpiParent, arg); + assert(arg); + } + + /* Get the net driver counts from the runtime. */ + vpip_count_drivers(arg, idx, counts); + num_drivers = counts[0] + counts[1] + counts[2]; + + /* Handle optional net_is_forced argument. */ + arg = vpi_scan(argv); + if (arg == 0) goto args_done; + val.value.integer = counts[3]; + vpi_put_value(arg, &val, 0, vpiNoDelay); + + /* Handle optional number_of_01x_drivers argument. */ + arg = vpi_scan(argv); + if (arg == 0) goto args_done; + val.value.integer = num_drivers; + vpi_put_value(arg, &val, 0, vpiNoDelay); + + /* Handle optional number_of_0_drivers argument. */ + arg = vpi_scan(argv); + if (arg == 0) goto args_done; + val.value.integer = counts[0]; + vpi_put_value(arg, &val, 0, vpiNoDelay); + + /* Handle optional number_of_1_drivers argument. */ + arg = vpi_scan(argv); + if (arg == 0) goto args_done; + val.value.integer = counts[1]; + vpi_put_value(arg, &val, 0, vpiNoDelay); + + /* Handle optional number_of_x_drivers argument. */ + arg = vpi_scan(argv); + if (arg == 0) goto args_done; + val.value.integer = counts[2]; + vpi_put_value(arg, &val, 0, vpiNoDelay); + + /* Free the argument iterator. */ + vpi_free_object(argv); + +args_done: + val.value.integer = (num_drivers > 1) ? 1 : 0; + vpi_put_value(callh, &val, 0, vpiNoDelay); + return 0; +} + +/* + * Routine to register the system tasks/functions provided in this file. + */ +void sys_countdrivers_register() +{ + s_vpi_systf_data tf_data; + vpiHandle res; + + tf_data.type = vpiSysFunc; + tf_data.tfname = "$countdrivers"; + tf_data.calltf = sys_countdrivers_calltf; + tf_data.compiletf = sys_countdrivers_compiletf; + tf_data.sizetf = 0; + tf_data.user_data = "$countdrivers"; + res = vpi_register_systf(&tf_data); + vpip_make_systf_system_defined(res); +} diff --git a/vpi/sys_icarus.c b/vpi/sys_icarus.c index d80a67074..40d8c52e3 100644 --- a/vpi/sys_icarus.c +++ b/vpi/sys_icarus.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008-2011 Cary R. (cygcary@yahoo.com) + * Copyright (C) 2008-2012 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 @@ -301,11 +301,6 @@ void sys_special_register(void) tf_data.type = vpiSysFunc; tf_data.sysfunctype = vpiIntFunc; - tf_data.tfname = "$countdrivers"; - tf_data.user_data = "$countdrivers"; - res = vpi_register_systf(&tf_data); - vpip_make_systf_system_defined(res); - tf_data.tfname = "$getpattern"; tf_data.user_data = "$getpattern"; res = vpi_register_systf(&tf_data); diff --git a/vpi/sys_table.c b/vpi/sys_table.c index 8a7dabffe..7010dd85b 100644 --- a/vpi/sys_table.c +++ b/vpi/sys_table.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2010,2012 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 @@ -24,6 +24,7 @@ # include extern void sys_convert_register(); +extern void sys_countdrivers_register(); extern void sys_fileio_register(); extern void sys_finish_register(); extern void sys_deposit_register(); @@ -195,6 +196,7 @@ static void sys_lxt_or_vcd_register() void (*vlog_startup_routines[])() = { sys_convert_register, + sys_countdrivers_register, sys_fileio_register, sys_finish_register, sys_deposit_register, diff --git a/vpi_user.h b/vpi_user.h index d0fe2b415..0660752d1 100644 --- a/vpi_user.h +++ b/vpi_user.h @@ -616,6 +616,17 @@ extern void vpip_set_return_value(int value); extern s_vpi_vecval vpip_calc_clog2(vpiHandle arg); extern void vpip_make_systf_system_defined(vpiHandle ref); + /* Return driver information for a net bit. The information is returned + in the 'counts' array as follows: + counts[0] - number of drivers driving '0' onto the net + counts[1] - number of drivers driving '1' onto the net + counts[2] - number of drivers driving 'X' onto the net + counts[3] - set to 1 if the net is forced, 0 otherwise + The 'ref' argument should reference a net. The 'idx' argument selects + which bit of the net is examined. */ +extern void vpip_count_drivers(vpiHandle ref, unsigned idx, + unsigned counts[4]); + EXTERN_C_END #endif diff --git a/vvp/island_tran.cc b/vvp/island_tran.cc index 5462f02a4..a3dee08ea 100644 --- a/vvp/island_tran.cc +++ b/vvp/island_tran.cc @@ -23,12 +23,16 @@ # include "schedule.h" # include +# include + using namespace std; class vvp_island_tran : public vvp_island { public: void run_island(); + void count_drivers(vvp_island_port*port, unsigned bit_idx, + unsigned counts[3]); }; enum tran_state_t { @@ -102,6 +106,18 @@ void vvp_island_tran::run_island() } } +static bool warn_count_drivers = true; + +void vvp_island_tran::count_drivers(vvp_island_port*port, unsigned bit_idx, + unsigned counts[3]) +{ + if (warn_count_drivers) { + cerr << "sorry: $countdrivers is not yet fully implemented." << endl; + cerr << " Some driver counts will not be correct." << endl; + warn_count_drivers = false; + } +} + bool vvp_island_branch_tran::run_test_enabled() { vvp_island_port*ep = en? dynamic_cast (en->fun) : 0; diff --git a/vvp/resolv.cc b/vvp/resolv.cc index d981d4881..26a00305e 100644 --- a/vvp/resolv.cc +++ b/vvp/resolv.cc @@ -178,6 +178,16 @@ void resolv_tri::recv_vec8_(unsigned port, const vvp_vector8_t&bit) net_->send_vec8(val_[base]); } +void resolv_tri::count_drivers(unsigned bit_idx, unsigned counts[3]) +{ + for (unsigned idx = 0 ; idx < nports_ ; idx += 1) { + if (val_[idx].size() == 0) + continue; + + update_driver_counts(val_[idx].value(bit_idx).value(), counts); + } +} + resolv_wired_logic::resolv_wired_logic(unsigned nports, vvp_net_t*net) : resolv_core(nports, net) @@ -253,6 +263,16 @@ void resolv_wired_logic::recv_vec8_(unsigned port, const vvp_vector8_t&bit) recv_vec4_(port, reduce4(bit)); } +void resolv_wired_logic::count_drivers(unsigned bit_idx, unsigned counts[3]) +{ + for (unsigned idx = 0 ; idx < nports_ ; idx += 1) { + if (val_[idx].size() == 0) + continue; + + update_driver_counts(val_[idx].value(bit_idx), counts); + } +} + resolv_triand::resolv_triand(unsigned nports, vvp_net_t*net) : resolv_wired_logic(nports, net) diff --git a/vvp/resolv.h b/vvp/resolv.h index f0a850861..6e14383a3 100644 --- a/vvp/resolv.h +++ b/vvp/resolv.h @@ -52,6 +52,8 @@ class resolv_core : public vvp_net_fun_t { unsigned base, unsigned wid, unsigned vwid) { recv_vec8_pv_(port.port(), bit, base, wid, vwid); } + virtual void count_drivers(unsigned bit_idx, unsigned counts[3]) =0; + private: friend class resolv_extend; virtual void recv_vec4_(unsigned port, const vvp_vector4_t&bit) =0; @@ -115,6 +117,8 @@ class resolv_tri : public resolv_core { vvp_scalar_t hiz_value); ~resolv_tri(); + void count_drivers(unsigned bit_idx, unsigned counts[3]); + private: void recv_vec4_(unsigned port, const vvp_vector4_t&bit); void recv_vec8_(unsigned port, const vvp_vector8_t&bit); @@ -141,6 +145,8 @@ class resolv_wired_logic : public resolv_core { explicit resolv_wired_logic(unsigned nports, vvp_net_t*net); virtual ~resolv_wired_logic(); + void count_drivers(unsigned bit_idx, unsigned counts[3]); + protected: virtual vvp_vector4_t wired_logic_math_(vvp_vector4_t&a, vvp_vector4_t&b) =0; diff --git a/vvp/vpi_priv.cc b/vvp/vpi_priv.cc index 5d6c8b96b..82f5c9368 100644 --- a/vvp/vpi_priv.cc +++ b/vvp/vpi_priv.cc @@ -1458,3 +1458,16 @@ extern "C" s_vpi_vecval vpip_calc_clog2(vpiHandle arg) rtn.bval = 0; return rtn; } + +/* + * This routine provides the information needed to implement $countdrivers. + * It is done here for performance reasons - interrogating the drivers + * individually via the VPI interface would be much slower. + */ +extern "C" void vpip_count_drivers(vpiHandle ref, unsigned idx, + unsigned counts[4]) +{ + struct __vpiSignal*rfp = dynamic_cast<__vpiSignal*>(ref); + assert(rfp); + rfp->node->count_drivers(idx, counts); +} diff --git a/vvp/vvp_island.h b/vvp/vvp_island.h index 2ff84027c..0e20f2c2f 100644 --- a/vvp/vvp_island.h +++ b/vvp/vvp_island.h @@ -55,7 +55,7 @@ */ struct vvp_island_branch; -class vvp_island_node; +class vvp_island_port; class vvp_island : private vvp_gen_event_s { @@ -74,6 +74,10 @@ class vvp_island : private vvp_gen_event_s { // method to give the island its character. virtual void run_island() =0; + // Support for $countdrivers. + virtual void count_drivers(vvp_island_port*port, unsigned bit_idx, + unsigned counts[3]) =0; + protected: // The base class collects a list of all the branches in the // island. The derived island class can access this list for @@ -144,6 +148,12 @@ class vvp_island_port : public vvp_net_fun_t { private: vvp_island*island_; + public: // Support for $countdrivers. + inline void count_drivers(unsigned bit_idx, unsigned counts[3]) + { + island_->count_drivers(this, bit_idx, counts); + } + private: // not implemented vvp_island_port(const vvp_island_port&); vvp_island_port& operator = (const vvp_island_port&); diff --git a/vvp/vvp_net.cc b/vvp/vvp_net.cc index 569f83ba7..526d1aeaa 100644 --- a/vvp/vvp_net.cc +++ b/vvp/vvp_net.cc @@ -19,7 +19,10 @@ # include "config.h" # include "vvp_net.h" +# include "vvp_net_sig.h" +# include "vvp_island.h" # include "vpi_priv.h" +# include "resolv.h" # include "schedule.h" # include "statistics.h" # include @@ -209,6 +212,36 @@ void vvp_net_t::unlink(vvp_net_ptr_t dst_ptr) net->port[net_port] = vvp_net_ptr_t(0,0); } +void vvp_net_t::count_drivers(unsigned idx, unsigned counts[4]) +{ + counts[0] = 0; + counts[1] = 0; + counts[2] = 0; + counts[3] = 0; + + /* $countdrivers can only be used on wires. */ + vvp_wire_base*wire=dynamic_cast(fil); + assert(wire); + + if (wire->is_forced(idx)) + counts[3] = 1; + + /* If the net has multiple drivers, we need to interrogate the + resolver network to get the driven values. */ + if (resolv_core*resolver = dynamic_cast(fun)) { + resolver->count_drivers(idx, counts); + return; + } + if (vvp_island_port*resolver = dynamic_cast(fun)) { + resolver->count_drivers(idx, counts); + return; + } + + /* If the functor is not a resolver, there is only one driver, so + we can just interrogate the filter to get the driven value. */ + update_driver_counts(wire->driven_value(idx), counts); +} + void vvp_net_fun_t::operator delete(void*) { assert(0); diff --git a/vvp/vvp_net.h b/vvp/vvp_net.h index e3456bbc7..8cd2d245c 100644 --- a/vvp/vvp_net.h +++ b/vvp/vvp_net.h @@ -1,7 +1,7 @@ #ifndef __vvp_net_H #define __vvp_net_H /* - * Copyright (c) 2004-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2004-2012 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 @@ -187,6 +187,24 @@ extern ostream& operator<< (ostream&o, vvp_bit4_t a); posedge, no edge, or negedge. */ extern int edge(vvp_bit4_t from, vvp_bit4_t to); + /* Support for $countdrivers. */ +inline void update_driver_counts(vvp_bit4_t bit, unsigned counts[3]) +{ + switch (bit) { + case BIT4_0: + counts[0] += 1; + break; + case BIT4_1: + counts[1] += 1; + break; + case BIT4_X: + counts[2] += 1; + break; + default: + break; + } +} + /* * This class represents scalar values collected into vectors. The * vector values can be accessed individually, or treated as a @@ -1100,6 +1118,9 @@ class vvp_net_t { void force_vec8(const vvp_vector8_t&val, vvp_vector2_t mask); void force_real(double val, vvp_vector2_t mask); + public: // Method to support $countdrivers + void count_drivers(unsigned idx, unsigned counts[4]); + private: vvp_net_ptr_t out_; diff --git a/vvp/vvp_net_sig.cc b/vvp/vvp_net_sig.cc index ce47a0959..0cdd96ec2 100644 --- a/vvp/vvp_net_sig.cc +++ b/vvp/vvp_net_sig.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2010 Stephen Williams (steve@icarus.com) + * Copyright (c) 2004-2010,2012 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 @@ -621,6 +621,18 @@ vvp_wire_base::~vvp_wire_base() { } +vvp_bit4_t vvp_wire_base::driven_value(unsigned) const +{ + assert(0); + return BIT4_X; +} + +bool vvp_wire_base::is_forced(unsigned) const +{ + assert(0); + return false; +} + vvp_wire_vec4::vvp_wire_vec4(unsigned wid, vvp_bit4_t init) : bits4_(wid, init) { @@ -795,6 +807,16 @@ void vvp_wire_vec4::vec4_value(vvp_vector4_t&val) const val.set_bit(idx, filtered_value_(idx)); } +vvp_bit4_t vvp_wire_vec4::driven_value(unsigned idx) const +{ + return bits4_.value(idx); +} + +bool vvp_wire_vec4::is_forced(unsigned idx) const +{ + return test_force_mask(idx); +} + vvp_wire_vec8::vvp_wire_vec8(unsigned wid) : bits8_(wid) { @@ -954,6 +976,16 @@ void vvp_wire_vec8::vec4_value(vvp_vector4_t&val) const val = reduce4(vec8_value()); } +vvp_bit4_t vvp_wire_vec8::driven_value(unsigned idx) const +{ + return bits8_.value(idx).value(); +} + +bool vvp_wire_vec8::is_forced(unsigned idx) const +{ + return test_force_mask(idx); +} + vvp_wire_real::vvp_wire_real() : bit_(0.0), force_(0.0) { diff --git a/vvp/vvp_net_sig.h b/vvp/vvp_net_sig.h index 92c5e0119..46d4979c8 100644 --- a/vvp/vvp_net_sig.h +++ b/vvp/vvp_net_sig.h @@ -1,7 +1,7 @@ #ifndef __vvp_net_sig_H #define __vvp_net_sig_H /* - * Copyright (c) 2004-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2004-2012 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 @@ -272,6 +272,10 @@ class vvp_wire_base : public vvp_net_fil_t, public vvp_signal_value { public: vvp_wire_base(); ~vvp_wire_base(); + + // Support for $countdrivers + virtual vvp_bit4_t driven_value(unsigned idx) const; + virtual bool is_forced(unsigned idx) const; }; class vvp_wire_vec4 : public vvp_wire_base { @@ -304,6 +308,10 @@ class vvp_wire_vec4 : public vvp_wire_base { vvp_scalar_t scalar_value(unsigned idx) const; void vec4_value(vvp_vector4_t&) const; + // Support for $countdrivers + vvp_bit4_t driven_value(unsigned idx) const; + bool is_forced(unsigned idx) const; + private: vvp_bit4_t filtered_value_(unsigned idx) const; @@ -347,6 +355,10 @@ class vvp_wire_vec8 : public vvp_wire_base { // This is new to vvp_wire_vec8 vvp_vector8_t vec8_value() const; + // Support for $countdrivers + vvp_bit4_t driven_value(unsigned idx) const; + bool is_forced(unsigned idx) const; + private: vvp_scalar_t filtered_value_(unsigned idx) const;