From 7eb0efd424b3083d5a619d835f4536e156ae74f4 Mon Sep 17 00:00:00 2001 From: Cary R Date: Sun, 31 May 2020 00:24:32 -0700 Subject: [PATCH] Add basic support for vpiBit --- vpi_user.h | 4 +- vvp/Makefile.in | 2 +- vvp/vpi_bit.cc | 238 ++++++++++++++++++++++++++++++++++++++++++++++ vvp/vpi_priv.cc | 4 + vvp/vpi_priv.h | 32 ++++++- vvp/vpi_signal.cc | 130 ++++++++++++++++++++++--- 6 files changed, 395 insertions(+), 15 deletions(-) create mode 100644 vvp/vpi_bit.cc diff --git a/vpi_user.h b/vpi_user.h index a918cbabc..43e9345b5 100644 --- a/vpi_user.h +++ b/vpi_user.h @@ -1,7 +1,7 @@ #ifndef VPI_USER_H #define VPI_USER_H /* - * Copyright (c) 1999-2019 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-2020 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 @@ -286,12 +286,14 @@ typedef struct t_vpi_delay { #define vpiNamedEvent 34 #define vpiNamedFork 35 #define vpiNet 36 +#define vpiNetBit 37 #define vpiParameter 41 #define vpiPartSelect 42 #define vpiPathTerm 43 #define vpiPort 44 #define vpiRealVar 47 #define vpiReg 48 +#define vpiRegBit 49 #define vpiSysFuncCall 56 #define vpiSysTaskCall 57 #define vpiTask 59 diff --git a/vvp/Makefile.in b/vvp/Makefile.in index bf04bd5b7..8ccdb1d2e 100644 --- a/vvp/Makefile.in +++ b/vvp/Makefile.in @@ -63,7 +63,7 @@ dllib=@DLLIB@ MDIR1 = -DMODULE_DIR1='"$(libdir)/ivl$(suffix)"' -VPI = vpi_modules.o vpi_callback.o vpi_cobject.o vpi_const.o vpi_darray.o \ +VPI = vpi_modules.o vpi_bit.o vpi_callback.o vpi_cobject.o vpi_const.o vpi_darray.o \ vpi_event.o vpi_iter.o vpi_mcd.o \ vpi_priv.o vpi_scope.o vpi_real.o vpi_signal.o vpi_string.o vpi_tasks.o vpi_time.o \ vpi_vthr_vector.o vpip_bin.o vpip_hex.o vpip_oct.o \ diff --git a/vvp/vpi_bit.cc b/vvp/vpi_bit.cc new file mode 100644 index 000000000..b6585d3b1 --- /dev/null +++ b/vvp/vpi_bit.cc @@ -0,0 +1,238 @@ +/* + * Copyright (c) 2020 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 + * 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. + */ + +/* + * vpiNetBit and vpiRegBit are handled here along with some help from their + * parent singal or net. + */ + +# include "compile.h" +# include "vpi_priv.h" +# include + + +static const __vpiBit*bit_from_handle(const __vpiHandle*ref) +{ + if (ref == NULL) return NULL; + const __vpiBit::as_bit_t*ptr = dynamic_cast (ref); + if (ptr == NULL) return NULL; + return (const struct __vpiBit*) ref; +} + +static __vpiBit*bit_from_handle(__vpiHandle*ref) +{ + if (ref == NULL) return NULL; + __vpiBit::as_bit_t*ptr = dynamic_cast<__vpiBit::as_bit_t*> (ref); + if (ptr == NULL) return NULL; + return (struct __vpiBit*) ref; +} + +static int bit_get_type(const __vpiBit*rfp) +{ + assert(rfp); + + const struct __vpiSignal*parent = rfp->get_parent(); + assert(parent); + + switch (parent->get_type_code()) { + case vpiNet: + return vpiNetBit; + case vpiReg: + return vpiRegBit; + } + assert(0); +} + +static int bit_get(int code, vpiHandle ref) +{ + struct __vpiBit*rfp = bit_from_handle(ref); + assert(rfp); + + struct __vpiSignal*parent = rfp->get_parent(); + assert(parent); + + switch (code) { + case vpiArray: // A bit is not an array + return 0; + + case vpiAutomatic: + return vpi_get(vpiAutomatic, parent); + + case vpiIndex: + { + s_vpi_value vp; + vp.format = vpiIntVal; + vpi_get_value(rfp->index, &vp); + return vp.value.integer; + } + + case vpiLineNo: + return vpi_get(vpiLineNo, parent); + + case vpiScalar: // A bit is a scalar + return 1; + + case vpiSigned: // A bit is unsigned + return 0; + + case vpiSize: // A bit has a width of 1 + return 1; + + case vpiVector: // A bit is not a vector + return 0; + +// FIXME: Do we need a _vpiFromThr or _vpiNexusID case? + + default: + fprintf(stderr, "VPI error: unknown bit_get property %d.\n", + code); + return vpiUndefined; + } +} + +static char* bit_get_str(int code, vpiHandle ref) +{ + struct __vpiBit*rfp = bit_from_handle(ref); + assert(rfp); + + if (code == vpiFile) { // Not implemented for now! + return simple_set_rbuf_str(file_names[0]); + } + + if ((code != vpiName) && (code != vpiFullName)) return NULL; + + struct __vpiSignal*parent = rfp->get_parent(); + assert(parent); + + char *nm, *ixs; + nm = strdup(vpi_get_str(vpiName, parent)); + s_vpi_value vp; + vp.format = vpiDecStrVal; + vpi_get_value(rfp->index, &vp); + ixs = vp.value.str; + + char *rbuf = generic_get_str(code, vpip_scope(parent), nm, ixs); + free(nm); + return rbuf; +} + +static vpiHandle bit_get_handle(int code, vpiHandle ref) +{ + struct __vpiBit*rfp = bit_from_handle(ref); + assert(rfp); + + struct __vpiSignal*parent = rfp->get_parent(); + assert(parent); + + switch (code) { + case vpiIndex: + return rfp->index; + + case vpiParent: + return parent; + + case vpiScope: + return vpi_handle(vpiScope, parent); + + case vpiModule: + return vpi_handle(vpiModule, parent); + } + + return 0; +} + +/* +static vpiHandle bit_iterate(int code, vpiHandle ref) +{ + struct __vpiBit*rfp = bit_from_handle(ref); + assert(rfp); + (void) code; + + return 0; +} + +static vpiHandle bit_index(int idx, vpiHandle ref) +{ + struct __vpiBit*rfp = bit_from_handle(ref); + assert(rfp); + (void) idx; + + return 0; +} +*/ + +static void bit_get_value(vpiHandle ref, s_vpi_value*vp) +{ + struct __vpiBit*rfp = bit_from_handle(ref); + assert(rfp); + + struct __vpiSignal*parent = rfp->get_parent(); + assert(parent); + + parent->get_bit_value(rfp, vp); +} + +static vpiHandle bit_put_value(vpiHandle ref, s_vpi_value*vp, int flags) +{ + struct __vpiBit*rfp = bit_from_handle(ref); + assert(rfp); + (void) vp; + (void) flags; + + fprintf(stderr, "Sorry: vpi_put_value() for %s type %s is not " + "implemented\n", vpi_get_str(vpiFullName, ref), + vpi_get_str(vpiType, ref)); + + // FIXME: Put the value to the net or reg bit. + + return ref; +} + + +int __vpiBit::get_index(void) const +{ + s_vpi_value vp; + vp.format = vpiIntVal; + vpi_get_value(index, &vp); + return vp.value.integer; +} + +int __vpiBit::as_bit_t::get_type_code(void) const +{ return bit_get_type(bit_from_handle(this)); } + +int __vpiBit::as_bit_t::vpi_get(int code) +{ return bit_get(code, this); } + +char* __vpiBit::as_bit_t::vpi_get_str(int code) +{ return bit_get_str(code, this); } + +void __vpiBit::as_bit_t::vpi_get_value(p_vpi_value val) +{ bit_get_value(this, val); } + +vpiHandle __vpiBit::as_bit_t::vpi_put_value(p_vpi_value val, int flags) +{ return bit_put_value(this, val, flags); } + +vpiHandle __vpiBit::as_bit_t::vpi_handle(int code) +{ return bit_get_handle(code, this); } + +//vpiHandle __vpiBit::as_bit_t::vpi_iterate(int code) // FIXME: Is this needed? +//{ return bit_iterate(code, this); } + +//vpiHandle __vpiBit::as_bit_t::vpi_index(int idx) // FIXME: Is this needed? +//{ return bit_index(idx, this); } diff --git a/vvp/vpi_priv.cc b/vvp/vpi_priv.cc index 44f402d86..42d301a50 100644 --- a/vvp/vpi_priv.cc +++ b/vvp/vpi_priv.cc @@ -355,6 +355,8 @@ static const char* vpi_type_values(PLI_INT32 code) return "vpiNet"; case vpiNetArray: return "vpiNetArray"; + case vpiNetBit: + return "vpiNetBit"; case vpiParameter: return "vpiParameter"; case vpiPartSelect: @@ -363,6 +365,8 @@ static const char* vpi_type_values(PLI_INT32 code) return "vpiRealVar"; case vpiReg: return "vpiReg"; + case vpiRegBit: + return "vpiRegBit"; case vpiShortIntVar: return "vpiShortIntVar"; case vpiStringVar: diff --git a/vvp/vpi_priv.h b/vvp/vpi_priv.h index 604745589..44ed61ab8 100644 --- a/vvp/vpi_priv.h +++ b/vvp/vpi_priv.h @@ -344,6 +344,11 @@ struct __vpiSignal : public __vpiHandle { public: unsigned width() const; + vpiHandle get_index(int index); + void get_bit_value(struct __vpiBit*bit, p_vpi_value vp); + void make_bits(); + + struct __vpiBit*bits; public: union { // The scope or parent array that contains me. @@ -366,7 +371,7 @@ struct __vpiSignal : public __vpiHandle { static void*operator new(std::size_t size); static void operator delete(void*); // not implemented protected: - inline __vpiSignal() { } + inline __vpiSignal() : bits(NULL) { } private: // Not implemented static void*operator new[] (std::size_t size); static void operator delete[](void*); @@ -384,6 +389,31 @@ extern vpiHandle vpip_make_net4(__vpiScope*scope, const char*name, int msb, int lsb, bool signed_flag, vvp_net_t*node); +/* + * This is used to represent a bit in a net/reg. + */ +struct __vpiBit { + struct as_bit_t : public __vpiHandle { + int get_type_code(void) const; + int vpi_get(int code); + char* vpi_get_str(int code); + void vpi_get_value(p_vpi_value val); + vpiHandle vpi_put_value(p_vpi_value val, int flags); + vpiHandle vpi_handle(int code); + } as_bit; + + vpiHandle index; + + union { + struct __vpiSignal*parent; + struct __vpiBit*bit0; + }; + + inline unsigned get_norm_index() const { return this - bit0; } + inline struct __vpiSignal*get_parent() const {return (bit0 - 1)->parent; } + int get_index(void) const; +}; + /* * This is used by system calls to represent a bit/part select of * a simple variable or constant array word. diff --git a/vvp/vpi_signal.cc b/vvp/vpi_signal.cc index 0c68643e6..ea85aef57 100644 --- a/vvp/vpi_signal.cc +++ b/vvp/vpi_signal.cc @@ -671,26 +671,125 @@ static vpiHandle signal_iterate(int code, vpiHandle ref) return 0; } +void __vpiSignal::make_bits() +{ + assert(bits == NULL); + bits = new struct __vpiBit[width() + 1]; + + // Make word[-1] point to the parent. + bits->parent = this; + // Now point to word[0]. + bits += 1; + + // Update each bit to point to the base + struct __vpiBit*base = bits; + for (unsigned idx = 0; idx < width(); idx += 1) { + base[idx].bit0 = base; + int real_idx; + if (msb.get_value() >= lsb.get_value()) { + real_idx = idx + lsb.get_value(); + } else { + real_idx = lsb.get_value() - idx; + } + base[idx].index = new __vpiDecConst(real_idx); + } +} + +vpiHandle __vpiSignal::get_index(int idx) +{ + /* Check to see if the index is in range. */ + if (msb.get_value() >= lsb.get_value()) { + if ((idx > msb.get_value()) || (idx < lsb.get_value())) return 0; + } else { + if ((idx < msb.get_value()) || (idx > lsb.get_value())) return 0; + } + + /* Normalize the index */ + unsigned norm_idx; + if (msb.get_value() >= lsb.get_value()) { + norm_idx = idx - lsb.get_value(); + } else { + norm_idx = lsb.get_value() - idx; + } + + if (bits == NULL) make_bits(); + + return &(bits[norm_idx].as_bit); +} + +void __vpiSignal::get_bit_value(struct __vpiBit*bit, p_vpi_value vp) +{ + unsigned index = bit->get_norm_index(); + + vvp_signal_value*vsig = dynamic_cast(node->fil); + assert(vsig); + + if (vp->format == vpiObjTypeVal) { + vp->format = vpiIntVal; + } + + switch (vp->format) { + case vpiBinStrVal: + format_vpiBinStrVal(vsig, index, 1, vp); + break; + + case vpiOctStrVal: + format_vpiOctStrVal(vsig, index, 1, vp); + break; + + case vpiDecStrVal: + format_vpiDecStrVal(vsig, index, 1, false, vp); + break; + + case vpiHexStrVal: + format_vpiHexStrVal(vsig, index, 1, vp); + break; + + case vpiStringVal: + format_vpiStringVal(vsig, index, 1, vp); + break; + + case vpiIntVal: + format_vpiIntVal(vsig, index, 1, false, vp); + break; + + case vpiRealVal: + format_vpiRealVal(vsig, index, 1, false, vp); + break; + + case vpiScalarVal: + format_vpiScalarVal(vsig, index, vp); + break; + + case vpiStrengthVal: + format_vpiStrengthVal(vsig, index, 1, vp); + break; + + case vpiVectorVal: + format_vpiVectorVal(vsig, index, 1, vp); + break; + + default: + fprintf(stderr, "internal error: get_value() " + "type %d is not implemented for bit " + "select %s[%d] in scope %s.\n", + (int)vp->format, vpi_get_str(vpiName), + bit->get_index(), + vpip_scope(this)->scope_name()); + assert(0); + }; +} + static vpiHandle signal_index(int idx, vpiHandle ref) { struct __vpiSignal*rfp = dynamic_cast<__vpiSignal*>(ref); assert(rfp); - /* Check to see if the index is in range. */ - if (rfp->msb.get_value() >= rfp->lsb.get_value()) { - if ((idx > rfp->msb.get_value()) || (idx < rfp->lsb.get_value())) return 0; - } else { - if ((idx < rfp->msb.get_value()) || (idx > rfp->lsb.get_value())) return 0; - } + /* We can only get the bit for a net or reg. */ PLI_INT32 type = vpi_get(vpiType, ref); if ((type != vpiNet) && (type != vpiReg)) return 0; - /* Return a vpiNetBit or vpiRegBit handle for the individual bit. */ - cerr << "Sorry: Icarus does not currently support " - << "vpi_get_handle_by_index() for " - << vpi_get_str(vpiType, ref); - cerr << " objects (" << vpi_get_str(vpiName, ref) << ")." << endl; - return 0; + return rfp->get_index(idx); } unsigned __vpiSignal::width(void) const @@ -1100,6 +1199,13 @@ void signal_delete(vpiHandle item) assert(obj->node->fil); obj->node->fil->clear_all_callbacks(); vvp_net_delete(obj->node); + if (obj->bits) { + for (unsigned idx=0; idxwidth(); idx+=1) { + delete obj->bits[idx].index; + } + obj->bits -= 1; + delete [] obj->bits; + } signal_dels += 1; VALGRIND_MEMPOOL_FREE(reinterpret_cast(obj)->pool, obj); }