From a1440ced8618159020a0e767e481d2bdf3b24d6e Mon Sep 17 00:00:00 2001 From: mole99 Date: Wed, 30 Aug 2023 09:50:00 +0200 Subject: [PATCH 1/7] Add support for annotation of input and output vectors --- vpi/sys_sdf.c | 42 ++++++++++++++++++++++ vpi_user.h | 2 ++ vvp/part.h | 3 ++ vvp/vpi_priv.cc | 93 +++++++++++++++++++++++++++++++++++++++++++++--- vvp/vpi_priv.h | 24 +++++++++++++ vvp/vpi_scope.cc | 83 ++++++++++++++++++++++++++++++++++++++++-- 6 files changed, 241 insertions(+), 6 deletions(-) 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); + } } From 023c5f27545794f97de142ae92e169853c1b8a7b Mon Sep 17 00:00:00 2001 From: mole99 Date: Wed, 30 Aug 2023 14:42:50 +0200 Subject: [PATCH 2/7] Add testcase with input and output vectors --- ivtest/gold/sdf_interconnect4-vvp-stdout.gold | 10 +++ ivtest/ivltests/sdf_interconnect4.sdf | 58 ++++++++++++++++ ivtest/ivltests/sdf_interconnect4.v | 67 +++++++++++++++++++ ivtest/regress-vvp.list | 1 + ivtest/vvp_tests/sdf_interconnect4.json | 6 ++ 5 files changed, 142 insertions(+) create mode 100644 ivtest/gold/sdf_interconnect4-vvp-stdout.gold create mode 100644 ivtest/ivltests/sdf_interconnect4.sdf create mode 100644 ivtest/ivltests/sdf_interconnect4.v create mode 100644 ivtest/vvp_tests/sdf_interconnect4.json diff --git a/ivtest/gold/sdf_interconnect4-vvp-stdout.gold b/ivtest/gold/sdf_interconnect4-vvp-stdout.gold new file mode 100644 index 000000000..d5bdbab9b --- /dev/null +++ b/ivtest/gold/sdf_interconnect4-vvp-stdout.gold @@ -0,0 +1,10 @@ +time=0 a=xxx b=xxx +time=5000 a=000 b=xxx +time=5140 a=000 b=xx0 +time=5160 a=000 b=x00 +time=5200 a=000 b=000 +time=15000 a=111 b=000 +time=15140 a=111 b=001 +time=15160 a=111 b=011 +time=15200 a=111 b=111 +ivltests/sdf_interconnect4.v:58: $finish called at 25000 (1ps) diff --git a/ivtest/ivltests/sdf_interconnect4.sdf b/ivtest/ivltests/sdf_interconnect4.sdf new file mode 100644 index 000000000..ee4a6f244 --- /dev/null +++ b/ivtest/ivltests/sdf_interconnect4.sdf @@ -0,0 +1,58 @@ +(DELAYFILE + (SDFVERSION "3.0") + (DESIGN "test") + (DATE "Wed Mar 8 12:34:56 2023") + (VENDOR "No Vendor") + (PROGRAM "Human") + (VERSION "1.0.0") + (DIVIDER .) + (VOLTAGE 5.5:5.0:4.5) + (PROCESS "best=0.65:nom=1.0:worst=1.8") + (TEMPERATURE -25.0:25.0:85.0) + (TIMESCALE 1 ns) + + (CELL + (CELLTYPE "my_design") + (INSTANCE) + (DELAY + (ABSOLUTE + (INTERCONNECT a[0] buffer0.in (0.000:0.020:0.000) (0.000:0.020:0.000)) + (INTERCONNECT buffer0.out b[0] (0.000:0.020:0.000) (0.000:0.020:0.000)) + (INTERCONNECT a[1] buffer1.in (0.000:0.030:0.000) (0.000:0.030:0.000)) + (INTERCONNECT buffer1.out b[1] (0.000:0.030:0.000) (0.000:0.030:0.000)) + (INTERCONNECT a[2] buffer2.in (0.000:0.050:0.000) (0.000:0.050:0.000)) + (INTERCONNECT buffer2.out b[2] (0.000:0.050:0.000) (0.000:0.050:0.000)) + ) + ) + ) + + (CELL + (CELLTYPE "buffer") + (INSTANCE buffer0) + (DELAY + (ABSOLUTE + (IOPATH in out (0.0:0.1:0.0) (0.0:0.1:0.0)) + ) + ) + ) + + (CELL + (CELLTYPE "buffer") + (INSTANCE buffer1) + (DELAY + (ABSOLUTE + (IOPATH in out (0.0:0.1:0.0) (0.0:0.1:0.0)) + ) + ) + ) + + (CELL + (CELLTYPE "buffer") + (INSTANCE buffer2) + (DELAY + (ABSOLUTE + (IOPATH in out (0.0:0.1:0.0) (0.0:0.1:0.0)) + ) + ) + ) +) diff --git a/ivtest/ivltests/sdf_interconnect4.v b/ivtest/ivltests/sdf_interconnect4.v new file mode 100644 index 000000000..b944ec719 --- /dev/null +++ b/ivtest/ivltests/sdf_interconnect4.v @@ -0,0 +1,67 @@ +`timescale 1ns/1ps + +/* + This design tests the interconnection delay + for three buffers in parallel with input and output vectors +*/ + +module buffer ( + input in, + output out +); + specify + (in => out) = (0.0:0.0:0.0); + endspecify + + assign out = in; + +endmodule + +module my_design ( + input [2:0] a, + output [2:0] b +); + + buffer buffer0 ( + .in (a[0]), + .out (b[0]) + ); + + buffer buffer1 ( + .in (a[1]), + .out (b[1]) + ); + + buffer buffer2 ( + .in (a[2]), + .out (b[2]) + ); + +endmodule + +module top; + + initial begin + $sdf_annotate("ivltests/sdf_interconnect4.sdf", my_design_inst); + $monitor("time=%0t a=%b b=%b", $realtime, a, b); + end + + reg [2:0] a; + wire [2:0] b; + + initial begin + #5; + a <= 3'b000; + #10; + a <= 3'b111; + #10; + $finish; + end + + my_design my_design_inst ( + .a (a), + .b (b) + ); + +endmodule + diff --git a/ivtest/regress-vvp.list b/ivtest/regress-vvp.list index 98907fc0d..bea6e5617 100644 --- a/ivtest/regress-vvp.list +++ b/ivtest/regress-vvp.list @@ -98,3 +98,4 @@ timing_check_delayed_signals vvp_tests/timing_check_delayed_signals.json sdf_interconnect1 vvp_tests/sdf_interconnect1.json sdf_interconnect2 vvp_tests/sdf_interconnect2.json sdf_interconnect3 vvp_tests/sdf_interconnect3.json +sdf_interconnect4 vvp_tests/sdf_interconnect4.json diff --git a/ivtest/vvp_tests/sdf_interconnect4.json b/ivtest/vvp_tests/sdf_interconnect4.json new file mode 100644 index 000000000..0704c6598 --- /dev/null +++ b/ivtest/vvp_tests/sdf_interconnect4.json @@ -0,0 +1,6 @@ +{ + "type" : "normal", + "source" : "sdf_interconnect4.v", + "iverilog-args" : [ "-Ttyp", "-ginterconnect", "-gspecify" ], + "gold" : "sdf_interconnect4" +} From f9d658caebd1183df10f5c8c3134087fa90e4782 Mon Sep 17 00:00:00 2001 From: mole99 Date: Mon, 4 Sep 2023 09:12:38 +0200 Subject: [PATCH 3/7] Add more debug information --- vvp/vpi_priv.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/vvp/vpi_priv.cc b/vvp/vpi_priv.cc index fce329b6d..792f6ab84 100644 --- a/vvp/vpi_priv.cc +++ b/vvp/vpi_priv.cc @@ -1640,6 +1640,9 @@ vpiHandle vpi_handle_multi(PLI_INT32 type, return nullptr; } + std::string port1_name(vpi_get_str(vpiName, ref1)); + std::string port2_name(vpi_get_str(vpiName, ref2)); + // If both ports are vpiOutput, we have to reassign the __vpiSignal from port1 // to port2 because otherwise the non-delayed version of the signal is dumped // even tho the intermodpath is correctly inserted @@ -1648,7 +1651,6 @@ vpiHandle vpi_handle_multi(PLI_INT32 type, if (port1->get_direction() == vpiOutput && port2->get_direction() == vpiOutput) { vpiHandle scope_port2 = vpi_handle(vpiScope, ref2); assert(scope_port2); - std::string port2_name(vpi_get_str(vpiName, ref2)); // Iterate over nets in the scope of port2 vpiHandle net_i = vpi_iterate(vpiNet, scope_port2) ; @@ -1771,7 +1773,7 @@ vpiHandle vpi_handle_multi(PLI_INT32 type, cur = cur.ptr()->port[cur.port()]; // Next net in linked list } - fprintf(stderr, "VPI error: Could not insert intermodpath!\n"); + fprintf(stderr, "VPI error: Could not insert intermodpath! port1 = %s, port2 = %s\n", port1_name.c_str(), port2_name.c_str()); return nullptr; } From b8ae6b1686427059b219cd39f87eb37b926d0622 Mon Sep 17 00:00:00 2001 From: mole99 Date: Mon, 4 Sep 2023 11:31:35 +0200 Subject: [PATCH 4/7] Fix port bit index --- vpi/sys_sdf.c | 4 ++-- vvp/vpi_priv.cc | 24 +++++++++++++++--------- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/vpi/sys_sdf.c b/vpi/sys_sdf.c index f554e0b66..1f2658b45 100644 --- a/vpi/sys_sdf.c +++ b/vpi/sys_sdf.c @@ -201,7 +201,7 @@ void sdf_interconnect_delays(struct interconnect_port_s port1, struct interconne 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) { + if (port1.has_index) { vpiHandle iter, vpi_port_bit; iter = vpi_iterate(vpiBit, port1_handle); @@ -222,7 +222,7 @@ void sdf_interconnect_delays(struct interconnect_port_s port1, struct interconne } // Check whether we have a single bit of a port for port2 - if (port2.index >= 0) { + if (port2.has_index) { vpiHandle iter, vpi_port_bit; iter = vpi_iterate(vpiBit, port2_handle); diff --git a/vvp/vpi_priv.cc b/vvp/vpi_priv.cc index 792f6ab84..6cc7e7330 100644 --- a/vvp/vpi_priv.cc +++ b/vvp/vpi_priv.cc @@ -1602,23 +1602,27 @@ 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 + // Indicates whether port1 refers to a single bit + bool port1_has_index = false; + int port1_bit_index = 0; vpiPortBitInfo* port1_bit = dynamic_cast(ref1); if (port1_bit) { // Get the bit index + port1_has_index = true; 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 + // Indicates whether port2 refers to a single bit + bool port2_has_index = false; + int port2_bit_index = 0; vpiPortBitInfo* port2_bit = dynamic_cast(ref2); if (port2_bit) { // Get the bit index + port2_has_index = true; port2_bit_index = vpi_get(vpiBit, port2_bit); // Update the ref1 to point to the base port ref2 = vpi_handle(vpiParent, port2_bit); @@ -1695,7 +1699,7 @@ vpiHandle vpi_handle_multi(PLI_INT32 type, // 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) { + if (port1_has_index) { vvp_net_ptr_t* net1_ptr = &net1->out_; // Search for part selects connected to port1 @@ -1728,8 +1732,8 @@ vpiHandle vpi_handle_multi(PLI_INT32 type, // 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))) { + if ( (!port2_has_index && cur.ptr() == net2) || + ( port2_has_index && 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 @@ -1755,7 +1759,7 @@ vpiHandle vpi_handle_multi(PLI_INT32 type, // 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) { + if (output_signal && !port2_has_index) { net2->fil = net1->fil; net1->fil = nullptr; output_signal->node = net2; @@ -1773,7 +1777,9 @@ vpiHandle vpi_handle_multi(PLI_INT32 type, cur = cur.ptr()->port[cur.port()]; // Next net in linked list } - fprintf(stderr, "VPI error: Could not insert intermodpath! port1 = %s, port2 = %s\n", port1_name.c_str(), port2_name.c_str()); + fprintf(stderr, "VPI error: Could not insert intermodpath!\n"); + fprintf(stderr, "\tport1 = %s, port1_has_index = %d, port1_bit_index = %d\n", port1_name.c_str(), port1_has_index, port1_bit_index); + fprintf(stderr, "\tport2 = %s, port2_has_index = %d, port2_bit_index = %d\n", port2_name.c_str(), port2_has_index, port2_bit_index); return nullptr; } From d70ad015f218e865bff39a83e4989de83259bdb8 Mon Sep 17 00:00:00 2001 From: mole99 Date: Mon, 4 Sep 2023 14:07:48 +0200 Subject: [PATCH 5/7] Cleanup --- vvp/vpi_priv.cc | 5 +++-- vvp/vpi_scope.cc | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/vvp/vpi_priv.cc b/vvp/vpi_priv.cc index 6cc7e7330..f92fdeea1 100644 --- a/vvp/vpi_priv.cc +++ b/vvp/vpi_priv.cc @@ -1644,8 +1644,9 @@ vpiHandle vpi_handle_multi(PLI_INT32 type, return nullptr; } - std::string port1_name(vpi_get_str(vpiName, ref1)); - std::string port2_name(vpi_get_str(vpiName, ref2)); + // Get the names of both ports + std::string port1_name(vpi_get_str(vpiName, ref1)); + std::string port2_name(vpi_get_str(vpiName, ref2)); // If both ports are vpiOutput, we have to reassign the __vpiSignal from port1 // to port2 because otherwise the non-delayed version of the signal is dumped diff --git a/vvp/vpi_scope.cc b/vvp/vpi_scope.cc index da90e4313..a30786ebb 100644 --- a/vvp/vpi_scope.cc +++ b/vvp/vpi_scope.cc @@ -799,7 +799,7 @@ vpiHandle vpiPortBitInfo::vpi_handle(int code) int vpiPortBitInfo::vpi_get(int code) { switch( code ) { - case vpiBit : // TODO is this correct? + case vpiBit : return bit_; default : break; From 18f6dcb6ba050565fe839badc3bbac5bebcf4707 Mon Sep 17 00:00:00 2001 From: mole99 Date: Mon, 4 Sep 2023 14:27:46 +0200 Subject: [PATCH 6/7] Fix formatting in sdf_parse.y --- vpi/sdf_parse.y | 156 ++++++++++++++++++++++++++---------------------- 1 file changed, 84 insertions(+), 72 deletions(-) diff --git a/vpi/sdf_parse.y b/vpi/sdf_parse.y index 70f0b6af5..029a11762 100644 --- a/vpi/sdf_parse.y +++ b/vpi/sdf_parse.y @@ -86,7 +86,7 @@ source_file : '(' K_DELAYFILE sdf_header_list cell_list ')' | '(' K_DELAYFILE error ')' { vpi_printf("SDF ERROR: %s:%d: Invalid DELAYFILE format\n", - sdf_parse_path, @2.first_line); + sdf_parse_path, @2.first_line); } ; @@ -111,48 +111,60 @@ sdf_header_item sdfversion : '(' K_SDFVERSION QSTRING ')' - { if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Version: %s\n", - sdf_parse_path, @2.first_line, $3); - free($3); + { if (sdf_flag_inform) { + vpi_printf("SDF INFO: %s:%d: Version: %s\n", + sdf_parse_path, @2.first_line, $3); + } + free($3); } ; design_name : '(' K_DESIGN QSTRING ')' - { if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Design: %s\n", - sdf_parse_path, @2.first_line, $3); - free($3); + { if (sdf_flag_inform) { + vpi_printf("SDF INFO: %s:%d: Design: %s\n", + sdf_parse_path, @2.first_line, $3); + } + free($3); } ; date : '(' K_DATE QSTRING ')' - { if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Date: %s\n", - sdf_parse_path, @2.first_line, $3); - free($3); + { if (sdf_flag_inform) { + vpi_printf("SDF INFO: %s:%d: Date: %s\n", + sdf_parse_path, @2.first_line, $3); + } + free($3); } ; vendor : '(' K_VENDOR QSTRING ')' - { if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Vendor: %s\n", - sdf_parse_path, @2.first_line, $3); - free($3); + { if (sdf_flag_inform) { + vpi_printf("SDF INFO: %s:%d: Vendor: %s\n", + sdf_parse_path, @2.first_line, $3); + } + free($3); } ; program_name : '(' K_PROGRAM QSTRING ')' - { if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Program: %s\n", - sdf_parse_path, @2.first_line, $3); - free($3); + { if (sdf_flag_inform) { + vpi_printf("SDF INFO: %s:%d: Program: %s\n", + sdf_parse_path, @2.first_line, $3); + } + free($3); } ; program_version : '(' K_VERSION QSTRING ')' - { if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Program Version: %s\n", - sdf_parse_path, @2.first_line, $3); + { if (sdf_flag_inform) { + vpi_printf("SDF INFO: %s:%d: Program Version: %s\n", + sdf_parse_path, @2.first_line, $3); + } free($3); } ; @@ -160,42 +172,42 @@ program_version hierarchy_divider : '(' K_DIVIDER '.' ')' { sdf_use_hchar = '.'; - if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Divider: \"%c\"\n", - sdf_parse_path, @1.first_line, sdf_use_hchar); + if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Divider: \"%c\"\n", + sdf_parse_path, @1.first_line, sdf_use_hchar); } | '(' K_DIVIDER '/' ')' { sdf_use_hchar = '/'; - if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Divider: \"%c\"\n", - sdf_parse_path, @1.first_line, sdf_use_hchar); + if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Divider: \"%c\"\n", + sdf_parse_path, @1.first_line, sdf_use_hchar); } | '(' K_DIVIDER HCHAR ')' { /* sdf_use_hchar no-change */ - if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Divider: \"%c\"\n", - sdf_parse_path, @1.first_line, sdf_use_hchar); + if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Divider: \"%c\"\n", + sdf_parse_path, @1.first_line, sdf_use_hchar); } ; voltage : '(' K_VOLTAGE rtriple ')' { /* The value must be defined. */ - if (! $3.defined) { - vpi_printf("SDF ERROR: %s:%d: Chosen value not defined.\n", - sdf_parse_path, @1.first_line); - } else if (sdf_flag_inform) { - vpi_printf("SDF INFO: %s:%d: Voltage: %f\n", - sdf_parse_path, @2.first_line, $3.value); - } + if (! $3.defined) { + vpi_printf("SDF ERROR: %s:%d: Chosen value not defined.\n", + sdf_parse_path, @1.first_line); + } else if (sdf_flag_inform) { + vpi_printf("SDF INFO: %s:%d: Voltage: %f\n", + sdf_parse_path, @2.first_line, $3.value); + } } | '(' K_VOLTAGE signed_real_number ')' { if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Voltage: %f\n", - sdf_parse_path, @2.first_line, $3); + sdf_parse_path, @2.first_line, $3); } ; process : '(' K_PROCESS QSTRING ')' { if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Process: %s\n", - sdf_parse_path, @2.first_line, $3); + sdf_parse_path, @2.first_line, $3); free($3); } ; @@ -203,26 +215,31 @@ process temperature : '(' K_TEMPERATURE rtriple ')' { /* The value must be defined. */ - if (! $3.defined) vpi_printf("SDF ERROR: %s:%d: Chosen value not defined.\n", - sdf_parse_path, @1.first_line); - else if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Temperature: %f\n", - sdf_parse_path, @2.first_line, $3.value); + if (! $3.defined) { + vpi_printf("SDF ERROR: %s:%d: Chosen value not defined.\n", + sdf_parse_path, @1.first_line); + } else if (sdf_flag_inform) { + vpi_printf("SDF INFO: %s:%d: Temperature: %f\n", + sdf_parse_path, @2.first_line, $3.value); + } } | '(' K_TEMPERATURE signed_real_number ')' - { if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Temperature: %f\n", - sdf_parse_path, @2.first_line, $3); + { if (sdf_flag_inform) { + vpi_printf("SDF INFO: %s:%d: Temperature: %f\n", + sdf_parse_path, @2.first_line, $3); + } } ; time_scale : '(' K_TIMESCALE REAL_NUMBER IDENTIFIER ')' { if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Timescale: %f%s\n", - sdf_parse_path, @2.first_line, $3, $4); + sdf_parse_path, @2.first_line, $3, $4); free($4); } | '(' K_TIMESCALE INTEGER IDENTIFIER ')' { if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Timescale: %lu%s\n", - sdf_parse_path, @2.first_line, $3, $4); + sdf_parse_path, @2.first_line, $3, $4); free($4); } ; @@ -272,13 +289,13 @@ timing_spec : '(' K_DELAY deltype_list ')' | '(' K_DELAY error ')' { vpi_printf("SDF ERROR: %s:%d: Syntax error in CELL DELAY SPEC\n", - sdf_parse_path, @2.first_line); } + sdf_parse_path, @2.first_line); } | '(' K_TIMINGCHECK tchk_def_list ')' { vpi_printf("SDF WARNING: %s:%d: TIMINGCHECK not supported.\n", - sdf_parse_path, @2.first_line); } + sdf_parse_path, @2.first_line); } | '(' K_TIMINGCHECK error ')' { vpi_printf("SDF ERROR: %s:%d: Syntax error in TIMINGCHECK SPEC\n", - sdf_parse_path, @2.first_line); } + sdf_parse_path, @2.first_line); } ; deltype_list @@ -293,7 +310,7 @@ deltype | '(' K_INCREMENT del_def_list ')' | '(' error ')' { vpi_printf("SDF ERROR: %s:%d: Invalid/malformed delay type\n", - sdf_parse_path, @1.first_line); } + sdf_parse_path, @1.first_line); } ; del_def_list @@ -309,54 +326,51 @@ del_def } | '(' K_IOPATH error ')' { vpi_printf("SDF ERROR: %s:%d: Invalid/malformed IOPATH\n", - sdf_parse_path, @2.first_line); } + sdf_parse_path, @2.first_line); } | '(' K_COND conditional_port_expr '(' K_IOPATH port_spec port_instance delval_list ')' ')' { if (sdf_flag_warning) vpi_printf("SDF WARNING: %s:%d: " - "COND not supported.\n", - sdf_parse_path, @2.first_line); + "COND not supported.\n", + sdf_parse_path, @2.first_line); free($6.string_val); free($7); } | '(' K_COND QSTRING conditional_port_expr '(' K_IOPATH port_spec port_instance delval_list ')' ')' { if (sdf_flag_warning) vpi_printf("SDF WARNING: %s:%d: " - "COND not supported.\n", - sdf_parse_path, @2.first_line); + "COND not supported.\n", + sdf_parse_path, @2.first_line); free($3); free($7.string_val); free($8); } | '(' K_COND error ')' { vpi_printf("SDF ERROR: %s:%d: Invalid/malformed COND\n", - sdf_parse_path, @2.first_line); } + sdf_parse_path, @2.first_line); } | '(' K_CONDELSE '(' K_IOPATH port_spec port_instance delval_list ')' ')' { if (sdf_flag_warning) vpi_printf("SDF WARNING: %s:%d: " - "CONDELSE not supported.\n", - sdf_parse_path, @2.first_line); + "CONDELSE not supported.\n", + sdf_parse_path, @2.first_line); free($5.string_val); free($6); } | '(' K_CONDELSE error ')' { vpi_printf("SDF ERROR: %s:%d: Invalid/malformed CONDELSE\n", - sdf_parse_path, @2.first_line); } + sdf_parse_path, @2.first_line); } /* | '(' K_INTERCONNECT port_instance port_instance delval_list ')' */ | '(' K_INTERCONNECT port_interconnect port_interconnect delval_list ')' - { - if (sdf_flag_inform) { - vpi_printf("SDF INFO: %s:%d: INTERCONNECT with " - "port1 = %s index = %d, port2 = %s index = %d\n", - sdf_parse_path, @2.first_line, $3.name, $3.index, $4.name, $4.index); - } - - sdf_interconnect_delays($3, $4, &$5, @2.first_line); - - free($3.name); - free($4.name); + { if (sdf_flag_inform) { + vpi_printf("SDF INFO: %s:%d: INTERCONNECT with " + "port1 = %s index = %d, port2 = %s index = %d\n", + sdf_parse_path, @2.first_line, $3.name, $3.index, $4.name, $4.index); + } + sdf_interconnect_delays($3, $4, &$5, @2.first_line); + free($3.name); + free($4.name); } | '(' K_INTERCONNECT error ')' { vpi_printf("SDF ERROR: %s:%d: Invalid/malformed INTERCONNECT\n", - sdf_parse_path, @2.first_line); + sdf_parse_path, @2.first_line); } ; @@ -471,14 +485,12 @@ port port_interconnect : hierarchical_identifier - { - struct interconnect_port_s tmp = {$1, false, 0}; - $$ = tmp; + { struct interconnect_port_s tmp = {$1, false, 0}; + $$ = tmp; } | hierarchical_identifier '[' INTEGER ']' - { - struct interconnect_port_s tmp = {$1, true, $3}; - $$ = tmp; + { struct interconnect_port_s tmp = {$1, true, $3}; + $$ = tmp; } ; From d7c6d7ce760f857a504978cf5a80226f25989793 Mon Sep 17 00:00:00 2001 From: mole99 Date: Mon, 4 Sep 2023 15:20:31 +0200 Subject: [PATCH 7/7] Fix memory leak and add vpi_release_handle() --- vpi/libvpi.c | 5 +++++ vpi/sys_sdf.c | 4 ++++ vpi_modules.cc | 1 + vpi_user.h | 2 ++ vvp/vpi_priv.cc | 11 ++++++++++- vvp/vvp.def | 1 + 6 files changed, 23 insertions(+), 1 deletion(-) diff --git a/vpi/libvpi.c b/vpi/libvpi.c index 100d6f084..cf4c2ee72 100644 --- a/vpi/libvpi.c +++ b/vpi/libvpi.c @@ -218,6 +218,11 @@ PLI_INT32 vpi_free_object(vpiHandle ref) assert(vpip_routines); return vpip_routines->free_object(ref); } +PLI_INT32 vpi_release_handle(vpiHandle ref) +{ + assert(vpip_routines); + return vpip_routines->release_handle(ref); +} PLI_INT32 vpi_get_vlog_info(p_vpi_vlog_info info) { assert(vpip_routines); diff --git a/vpi/sys_sdf.c b/vpi/sys_sdf.c index 1f2658b45..830837a48 100644 --- a/vpi/sys_sdf.c +++ b/vpi/sys_sdf.c @@ -207,6 +207,7 @@ void sdf_interconnect_delays(struct interconnect_port_s port1, struct interconne if (!iter) { vpi_printf("SDF ERROR: %s:%d: Could not find vpiBit iterator for port1!\n", sdf_fname, sdf_lineno); + return; } while ((vpi_port_bit = vpi_scan(iter))) { @@ -216,6 +217,7 @@ void sdf_interconnect_delays(struct interconnect_port_s port1, struct interconne 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; + vpi_release_handle(iter); // Free the iterator break; } } @@ -228,6 +230,7 @@ void sdf_interconnect_delays(struct interconnect_port_s port1, struct interconne if (!iter) { vpi_printf("SDF ERROR: %s:%d: Could not find vpiBit iterator for port2!\n", sdf_fname, sdf_lineno); + return; } while ((vpi_port_bit = vpi_scan(iter))) { @@ -237,6 +240,7 @@ void sdf_interconnect_delays(struct interconnect_port_s port1, struct interconne 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; + vpi_release_handle(iter); // Free the iterator break; } } diff --git a/vpi_modules.cc b/vpi_modules.cc index ab8f86f7c..26ccd395f 100644 --- a/vpi_modules.cc +++ b/vpi_modules.cc @@ -96,6 +96,7 @@ PLI_INT32 vpi_vprintf(const char*, va_list) { return 0; } PLI_INT32 vpi_chk_error(p_vpi_error_info) { return 0; } PLI_INT32 vpi_compare_objects(vpiHandle, vpiHandle) { return 0; } PLI_INT32 vpi_free_object(vpiHandle) { return 0; } +PLI_INT32 vpi_release_handle(vpiHandle) { return 0; } PLI_INT32 vpi_get_vlog_info(p_vpi_vlog_info info) { info->argc = 0; diff --git a/vpi_user.h b/vpi_user.h index a35ce5d15..40bf4879d 100644 --- a/vpi_user.h +++ b/vpi_user.h @@ -567,6 +567,7 @@ extern vpiHandle vpi_put_value(vpiHandle obj, p_vpi_value value, p_vpi_time when, PLI_INT32 flags); extern PLI_INT32 vpi_free_object(vpiHandle ref); +extern PLI_INT32 vpi_release_handle(vpiHandle ref); extern PLI_INT32 vpi_get_vlog_info(p_vpi_vlog_info vlog_info_p); /* @@ -724,6 +725,7 @@ typedef struct { PLI_INT32 (*chk_error)(p_vpi_error_info); PLI_INT32 (*compare_objects)(vpiHandle, vpiHandle); PLI_INT32 (*free_object)(vpiHandle); + PLI_INT32 (*release_handle)(vpiHandle); PLI_INT32 (*get_vlog_info)(p_vpi_vlog_info info) ; void (*vcontrol)(PLI_INT32, va_list); PLI_INT32 (*fopen)(const char*, const char*); diff --git a/vvp/vpi_priv.cc b/vvp/vpi_priv.cc index f92fdeea1..6d6422d56 100644 --- a/vvp/vpi_priv.cc +++ b/vvp/vpi_priv.cc @@ -291,6 +291,14 @@ PLI_INT32 vpi_free_object(vpiHandle ref) return rtn; } +PLI_INT32 vpi_release_handle(vpiHandle ref) +{ + // Since SystemVerilog vpi_free_object() has been + // renamed vpi_release_handle(), and thus + // vpi_free_object() has been deprecated. + return vpi_free_object(ref); +} + static int vpip_get_global(int property) { switch (property) { @@ -1575,7 +1583,7 @@ bool check_connected_to_concat8(vvp_net_t* current_net, vvp_net_t* net2) // net2 is connected if (cur.ptr() == net2) { - return true; + return true; } // Next net in linked list @@ -2002,6 +2010,7 @@ vpip_routines_s vpi_routines = { .chk_error = vpi_chk_error, .compare_objects = vpi_compare_objects, .free_object = vpi_free_object, + .release_handle = vpi_release_handle, .get_vlog_info = vpi_get_vlog_info, .vcontrol = vpi_sim_vcontrol, .fopen = vpi_fopen, diff --git a/vvp/vvp.def b/vvp/vvp.def index 7e7da212c..cbc478bbb 100644 --- a/vvp/vvp.def +++ b/vvp/vvp.def @@ -32,6 +32,7 @@ vpi_put_userdata vpi_put_value vpi_register_cb vpi_register_systf +vpi_release_handle vpi_remove_cb vpi_scan vpi_sim_control