Add basic support for vpiBit
This commit is contained in:
parent
a1518b5761
commit
7eb0efd424
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 \
|
||||
|
|
|
|||
|
|
@ -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 <cassert>
|
||||
|
||||
|
||||
static const __vpiBit*bit_from_handle(const __vpiHandle*ref)
|
||||
{
|
||||
if (ref == NULL) return NULL;
|
||||
const __vpiBit::as_bit_t*ptr = dynamic_cast<const __vpiBit::as_bit_t*> (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); }
|
||||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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<vvp_signal_value*>(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; idx<obj->width(); idx+=1) {
|
||||
delete obj->bits[idx].index;
|
||||
}
|
||||
obj->bits -= 1;
|
||||
delete [] obj->bits;
|
||||
}
|
||||
signal_dels += 1;
|
||||
VALGRIND_MEMPOOL_FREE(reinterpret_cast<vpiSignal_plug *>(obj)->pool, obj);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue