diff --git a/vpi/sys_sdf.c b/vpi/sys_sdf.c index 54a3203fe..f554e0b66 100644 --- a/vpi/sys_sdf.c +++ b/vpi/sys_sdf.c @@ -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); diff --git a/vpi_user.h b/vpi_user.h index e57983a08..a35ce5d15 100644 --- a/vpi_user.h +++ b/vpi_user.h @@ -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 diff --git a/vvp/part.h b/vvp/part.h index 433477e20..473a286c9 100644 --- a/vvp/part.h +++ b/vvp/part.h @@ -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_; diff --git a/vvp/vpi_priv.cc b/vvp/vpi_priv.cc index ac7ea6450..fce329b6d 100644 --- a/vvp/vpi_priv.cc +++ b/vvp/vpi_priv.cc @@ -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(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(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(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(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(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(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; diff --git a/vvp/vpi_priv.h b/vvp/vpi_priv.h index 3ebaa820e..1c5f01652 100644 --- a/vvp/vpi_priv.h +++ b/vvp/vpi_priv.h @@ -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 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. diff --git a/vvp/vpi_scope.cc b/vvp/vpi_scope.cc index 8a6f72912..da90e4313 100644 --- a/vvp/vpi_scope.cc +++ b/vvp/vpi_scope.cc @@ -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(ref); + assert(rfp); + unsigned width = rfp->get_width(); + + switch (code) { + case vpiBit: { + vpiHandle*args = (vpiHandle*)calloc(width, sizeof(vpiHandle*)); + + for (unsigned i = 0; iport_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(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; iadd_port_bit(obj_bit); + vpip_attach_to_current_scope(obj_bit); + } }