Add support for annotation of input and output vectors
This commit is contained in:
parent
7e62a1b848
commit
a1440ced86
|
|
@ -200,6 +200,48 @@ void sdf_interconnect_delays(struct interconnect_port_s port1, struct interconne
|
|||
vpiHandle port1_handle = get_port_handle(port1.name, sdf_lineno);
|
||||
vpiHandle port2_handle = get_port_handle(port2.name, sdf_lineno);
|
||||
|
||||
// Check whether we have a single bit of a port for port1
|
||||
if (port1.index >= 0) {
|
||||
vpiHandle iter, vpi_port_bit;
|
||||
iter = vpi_iterate(vpiBit, port1_handle);
|
||||
|
||||
if (!iter) {
|
||||
vpi_printf("SDF ERROR: %s:%d: Could not find vpiBit iterator for port1!\n", sdf_fname, sdf_lineno);
|
||||
}
|
||||
|
||||
while ((vpi_port_bit = vpi_scan(iter))) {
|
||||
int bit = vpi_get(vpiBit, vpi_port_bit);
|
||||
|
||||
// If we found the correct vpiPortBit, replace the port with it
|
||||
if (port1.index == bit) {
|
||||
if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Substituting vpiPort with vpiPortBit for port1\n", sdf_fname, sdf_lineno);
|
||||
port1_handle = vpi_port_bit;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check whether we have a single bit of a port for port2
|
||||
if (port2.index >= 0) {
|
||||
vpiHandle iter, vpi_port_bit;
|
||||
iter = vpi_iterate(vpiBit, port2_handle);
|
||||
|
||||
if (!iter) {
|
||||
vpi_printf("SDF ERROR: %s:%d: Could not find vpiBit iterator for port2!\n", sdf_fname, sdf_lineno);
|
||||
}
|
||||
|
||||
while ((vpi_port_bit = vpi_scan(iter))) {
|
||||
int bit = vpi_get(vpiBit, vpi_port_bit);
|
||||
|
||||
// If we found the correct vpiPortBit, replace the port with it
|
||||
if (port2.index == bit) {
|
||||
if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Substituting vpiPort with vpiPortBit for port2\n", sdf_fname, sdf_lineno);
|
||||
port2_handle = vpi_port_bit;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (port1_handle && port2_handle) {
|
||||
// Get interModPath for the two ports
|
||||
vpiHandle intermodpath = vpi_handle_multi(vpiInterModPath, port1_handle, port2_handle);
|
||||
|
|
|
|||
|
|
@ -292,6 +292,7 @@ typedef struct t_vpi_delay {
|
|||
#define vpiPartSelect 42
|
||||
#define vpiPathTerm 43
|
||||
#define vpiPort 44
|
||||
#define vpiPortBit 45
|
||||
#define vpiRealVar 47
|
||||
#define vpiReg 48
|
||||
#define vpiRegBit 49
|
||||
|
|
@ -309,6 +310,7 @@ typedef struct t_vpi_delay {
|
|||
#define vpiScope 84
|
||||
#define vpiSysTfCall 85
|
||||
#define vpiArgument 89
|
||||
#define vpiBit 90
|
||||
#define vpiInternalScope 92
|
||||
#define vpiModPathIn 95
|
||||
#define vpiModPathOut 96
|
||||
|
|
|
|||
|
|
@ -34,6 +34,9 @@ class vvp_fun_part : public vvp_net_fun_t {
|
|||
vvp_fun_part(unsigned base, unsigned wid);
|
||||
~vvp_fun_part();
|
||||
|
||||
unsigned get_base() const { return base_; }
|
||||
unsigned get_wid() const { return wid_; }
|
||||
|
||||
protected:
|
||||
unsigned base_;
|
||||
unsigned wid_;
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
# include "vpi_priv.h"
|
||||
# include "schedule.h"
|
||||
# include "logic.h"
|
||||
# include "part.h"
|
||||
#ifdef CHECK_WITH_VALGRIND
|
||||
# include "vvp_cleanup.h"
|
||||
#endif
|
||||
|
|
@ -1555,6 +1556,36 @@ vpiHandle vpi_handle_by_name(const char *name, vpiHandle scope)
|
|||
return out;
|
||||
}
|
||||
|
||||
// Check if net2 is connected to current_net through a net of vvp_fun_concat8s
|
||||
bool check_connected_to_concat8(vvp_net_t* current_net, vvp_net_t* net2)
|
||||
{
|
||||
if (!dynamic_cast<vvp_fun_concat8*>(current_net->fun)) return false;
|
||||
|
||||
vvp_net_ptr_t cur = current_net->out_;
|
||||
|
||||
// For everything connected
|
||||
while (cur.ptr()) {
|
||||
// Check if it's a concat8
|
||||
if (dynamic_cast<vvp_fun_concat8*>(cur.ptr()->fun)) {
|
||||
// Pass on the return value if found
|
||||
if (check_connected_to_concat8(cur.ptr(), net2)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// net2 is connected
|
||||
if (cur.ptr() == net2) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Next net in linked list
|
||||
cur = cur.ptr()->port[cur.port()];
|
||||
}
|
||||
|
||||
// net2 is not connected to this concat8
|
||||
return false;
|
||||
}
|
||||
|
||||
// Used to get intermodpath for two ports
|
||||
vpiHandle vpi_handle_multi(PLI_INT32 type,
|
||||
vpiHandle ref1,
|
||||
|
|
@ -1571,6 +1602,28 @@ vpiHandle vpi_handle_multi(PLI_INT32 type,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
// Indicates to which bit port1 refers to if it's a vpiPortBit
|
||||
int port1_bit_index = -1; // -1 means the port is not a vector
|
||||
vpiPortBitInfo* port1_bit = dynamic_cast<vpiPortBitInfo*>(ref1);
|
||||
|
||||
if (port1_bit) {
|
||||
// Get the bit index
|
||||
port1_bit_index = vpi_get(vpiBit, port1_bit);
|
||||
// Update the ref1 to point to the base port
|
||||
ref1 = vpi_handle(vpiParent, port1_bit);
|
||||
}
|
||||
|
||||
// Indicates to which bit port2 refers to if it's a vpiPortBit
|
||||
int port2_bit_index = -1; // -1 means the port is not a vector
|
||||
vpiPortBitInfo* port2_bit = dynamic_cast<vpiPortBitInfo*>(ref2);
|
||||
|
||||
if (port2_bit) {
|
||||
// Get the bit index
|
||||
port2_bit_index = vpi_get(vpiBit, port2_bit);
|
||||
// Update the ref1 to point to the base port
|
||||
ref2 = vpi_handle(vpiParent, port2_bit);
|
||||
}
|
||||
|
||||
vpiPortInfo* port1 = dynamic_cast<vpiPortInfo*>(ref1);
|
||||
|
||||
if (!port1) {
|
||||
|
|
@ -1638,13 +1691,43 @@ vpiHandle vpi_handle_multi(PLI_INT32 type,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
// If port1 is actually a port bit, we have to get to the correct vvp_fun_part
|
||||
// after which we insert the intermodpath delay
|
||||
if (port1_bit_index >= 0) {
|
||||
vvp_net_ptr_t* net1_ptr = &net1->out_;
|
||||
|
||||
// Search for part selects connected to port1
|
||||
vvp_net_t* current_net = net1_ptr->ptr();
|
||||
|
||||
while (current_net) {
|
||||
if (!current_net) break; // End of list
|
||||
|
||||
vvp_fun_part* part = dynamic_cast<vvp_fun_part*>(current_net->fun);
|
||||
|
||||
// Its a part select!
|
||||
if (part) {
|
||||
// Is it the correct part select?
|
||||
if (part->get_base() == (unsigned)port1_bit_index) {
|
||||
assert(part->get_wid() == 1);
|
||||
net1 = current_net; // Replace net1 as this is our new start point
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
current_net = current_net->port[0].ptr(); // BUFT has only one input, index 0
|
||||
}
|
||||
}
|
||||
|
||||
// Iterate over all nodes connected to port1
|
||||
vvp_net_ptr_t cur = net1->out_;
|
||||
vvp_net_ptr_t prev = vvp_net_ptr_t(nullptr, 0);
|
||||
|
||||
while (cur.ptr()) {
|
||||
// Port2 is directly connected to port1
|
||||
if (cur.ptr() == net2) {
|
||||
// Either port2 is directly connected to port1
|
||||
// Or in the second case port2 is indirectly connected
|
||||
// to port1 through a net of concat8s
|
||||
if ( (port2_bit_index == -1 && cur.ptr() == net2) ||
|
||||
(port2_bit_index != -1 && check_connected_to_concat8(cur.ptr(), net2))) {
|
||||
vvp_net_t*new_net = new vvp_net_t;
|
||||
|
||||
// Create new node with intermodpath and connect port2 to it
|
||||
|
|
@ -1667,8 +1750,10 @@ vpiHandle vpi_handle_multi(PLI_INT32 type,
|
|||
cur.ptr()->port[cur.port()] = vvp_net_ptr_t(nullptr, 0); // Only port2 is connected to intermodpath
|
||||
}
|
||||
|
||||
// If both ports are vpiOutput, we have to reassign the __vpiSignal
|
||||
if (output_signal) {
|
||||
// If both ports are vpiOutput and port2 is not a vector,
|
||||
// we have to reassign the __vpiSignal so that the delayed
|
||||
// values get dumped
|
||||
if (output_signal && port2_bit_index == -1) {
|
||||
net2->fil = net1->fil;
|
||||
net1->fil = nullptr;
|
||||
output_signal->node = net2;
|
||||
|
|
|
|||
|
|
@ -432,6 +432,7 @@ struct __vpiBit {
|
|||
int get_index(void) const;
|
||||
};
|
||||
|
||||
class vpiPortBitInfo;
|
||||
|
||||
class vpiPortInfo : public __vpiHandle {
|
||||
public:
|
||||
|
|
@ -445,11 +446,17 @@ class vpiPortInfo : public __vpiHandle {
|
|||
|
||||
int get_type_code(void) const { return vpiPort; }
|
||||
int get_direction(void) { return direction_; }
|
||||
unsigned get_index(void) { return index_; }
|
||||
int get_width(void) { return width_; }
|
||||
void add_port_bit(vpiPortBitInfo* port_bit) { port_bits_.push_back(port_bit); }
|
||||
|
||||
int vpi_get(int code);
|
||||
char* vpi_get_str(int code);
|
||||
vpiHandle vpi_handle(int code);
|
||||
vvp_net_t* get_port(void) const { return ref_; }
|
||||
vpiHandle vpi_iterate(int code);
|
||||
|
||||
std::vector<vpiPortBitInfo*> port_bits_;
|
||||
|
||||
private:
|
||||
__vpiScope *parent_;
|
||||
|
|
@ -460,6 +467,23 @@ class vpiPortInfo : public __vpiHandle {
|
|||
vvp_net_t *ref_;
|
||||
};
|
||||
|
||||
class vpiPortBitInfo : public __vpiHandle {
|
||||
public:
|
||||
vpiPortBitInfo(vpiPortInfo *parent,
|
||||
unsigned bit);
|
||||
~vpiPortBitInfo();
|
||||
|
||||
int get_type_code(void) const { return vpiPortBit; }
|
||||
unsigned get_bit(void) const { return bit_; }
|
||||
|
||||
int vpi_get(int code);
|
||||
vpiHandle vpi_handle(int code);
|
||||
|
||||
private:
|
||||
vpiPortInfo *parent_;
|
||||
unsigned bit_;
|
||||
};
|
||||
|
||||
/*
|
||||
* This is used by system calls to represent a bit/part select of
|
||||
* a simple variable or constant array word.
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ void vpip_make_root_iterator(__vpiHandle**&table, unsigned&ntable)
|
|||
|
||||
#ifdef CHECK_WITH_VALGRIND
|
||||
void port_delete(__vpiHandle*handle);
|
||||
void port_bit_delete(__vpiHandle*handle);
|
||||
|
||||
/* Class definitions need to be cleaned up at the end. */
|
||||
static class_type **class_list = 0;
|
||||
|
|
@ -110,6 +111,9 @@ static void delete_sub_scopes(__vpiScope *scope)
|
|||
case vpiPort:
|
||||
port_delete(item);
|
||||
break;
|
||||
case vpiPortBit:
|
||||
port_bit_delete(item);
|
||||
break;
|
||||
case vpiStringVar:
|
||||
string_delete(item);
|
||||
break;
|
||||
|
|
@ -735,6 +739,74 @@ vpiHandle vpiPortInfo::vpi_handle(int code)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static vpiHandle portinfo_iterate(int code, vpiHandle ref)
|
||||
{
|
||||
vpiPortInfo*rfp = dynamic_cast<vpiPortInfo*>(ref);
|
||||
assert(rfp);
|
||||
unsigned width = rfp->get_width();
|
||||
|
||||
switch (code) {
|
||||
case vpiBit: {
|
||||
vpiHandle*args = (vpiHandle*)calloc(width, sizeof(vpiHandle*));
|
||||
|
||||
for (unsigned i = 0; i<rfp->port_bits_.size(); i++) {
|
||||
args[i] = rfp->port_bits_[i];
|
||||
}
|
||||
|
||||
return vpip_make_iterator(width, args, true);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
vpiHandle vpiPortInfo::vpi_iterate(int code)
|
||||
{
|
||||
return portinfo_iterate(code, this);
|
||||
}
|
||||
|
||||
|
||||
vpiPortBitInfo::vpiPortBitInfo(vpiPortInfo *parent,
|
||||
unsigned bit) :
|
||||
parent_(parent),
|
||||
bit_(bit)
|
||||
{
|
||||
}
|
||||
|
||||
vpiPortBitInfo::~vpiPortBitInfo()
|
||||
{
|
||||
}
|
||||
|
||||
#ifdef CHECK_WITH_VALGRIND
|
||||
void port_bit_delete(__vpiHandle *handle)
|
||||
{
|
||||
delete dynamic_cast<vpiPortBitInfo *>(handle);
|
||||
}
|
||||
#endif
|
||||
|
||||
vpiHandle vpiPortBitInfo::vpi_handle(int code)
|
||||
{
|
||||
|
||||
switch (code) {
|
||||
case vpiParent:
|
||||
return parent_;
|
||||
default :
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vpiPortBitInfo::vpi_get(int code)
|
||||
{
|
||||
switch( code ) {
|
||||
case vpiBit : // TODO is this correct?
|
||||
return bit_;
|
||||
default :
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Port info is meta-data to allow vpi queries of the port signature of modules for
|
||||
* code-generators etc. There are no actual nets corresponding to instances of module ports
|
||||
|
|
@ -742,7 +814,14 @@ vpiHandle vpiPortInfo::vpi_handle(int code)
|
|||
*/
|
||||
void compile_port_info( unsigned index, int vpi_direction, unsigned width, const char *name, char* buffer )
|
||||
{
|
||||
vpiHandle obj = new vpiPortInfo( vpip_peek_current_scope(),
|
||||
index, vpi_direction, width, name, buffer );
|
||||
vpiPortInfo* obj = new vpiPortInfo( vpip_peek_current_scope(),
|
||||
index, vpi_direction, width, name, buffer );
|
||||
vpip_attach_to_current_scope(obj);
|
||||
|
||||
// Create vpiPortBit objects
|
||||
for (unsigned i=0; i<width; i++) {
|
||||
vpiPortBitInfo* obj_bit = new vpiPortBitInfo(obj, i);
|
||||
obj->add_port_bit(obj_bit);
|
||||
vpip_attach_to_current_scope(obj_bit);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue