Merge pull request #994 from mole99/sdf-interconnect-vector

SDF: Interconnection delays for input/output vectors
This commit is contained in:
Cary R 2023-09-04 07:02:28 -07:00 committed by GitHub
commit 7ce068fbdb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 499 additions and 79 deletions

View File

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

View File

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

View File

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

View File

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

View File

@ -0,0 +1,6 @@
{
"type" : "normal",
"source" : "sdf_interconnect4.v",
"iverilog-args" : [ "-Ttyp", "-ginterconnect", "-gspecify" ],
"gold" : "sdf_interconnect4"
}

View File

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

View File

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

View File

@ -200,6 +200,52 @@ 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.has_index) {
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);
return;
}
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;
vpi_release_handle(iter); // Free the iterator
break;
}
}
}
// Check whether we have a single bit of a port for port2
if (port2.has_index) {
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);
return;
}
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;
vpi_release_handle(iter); // Free the iterator
break;
}
}
}
if (port1_handle && port2_handle) {
// Get interModPath for the two ports
vpiHandle intermodpath = vpi_handle_multi(vpiInterModPath, port1_handle, port2_handle);

View File

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

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
@ -565,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);
/*
@ -722,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*);

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
@ -290,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) {
@ -1555,6 +1564,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 +1610,32 @@ vpiHandle vpi_handle_multi(PLI_INT32 type,
return nullptr;
}
// Indicates whether port1 refers to a single bit
bool port1_has_index = false;
int port1_bit_index = 0;
vpiPortBitInfo* port1_bit = dynamic_cast<vpiPortBitInfo*>(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 whether port2 refers to a single bit
bool port2_has_index = false;
int port2_bit_index = 0;
vpiPortBitInfo* port2_bit = dynamic_cast<vpiPortBitInfo*>(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);
}
vpiPortInfo* port1 = dynamic_cast<vpiPortInfo*>(ref1);
if (!port1) {
@ -1587,6 +1652,10 @@ vpiHandle vpi_handle_multi(PLI_INT32 type,
return nullptr;
}
// 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
// even tho the intermodpath is correctly inserted
@ -1595,7 +1664,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) ;
@ -1638,13 +1706,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_has_index) {
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_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
@ -1667,8 +1765,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_has_index) {
net2->fil = net1->fil;
net1->fil = nullptr;
output_signal->node = net2;
@ -1687,6 +1787,8 @@ vpiHandle vpi_handle_multi(PLI_INT32 type,
}
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;
}
@ -1908,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,

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

View File

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