Add support for annotation of input and output vectors

This commit is contained in:
mole99 2023-08-30 09:50:00 +02:00
parent 7e62a1b848
commit a1440ced86
6 changed files with 241 additions and 6 deletions

View File

@ -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);

View File

@ -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

View File

@ -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_;

View File

@ -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;

View File

@ -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.

View File

@ -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);
}
}