Merge pull request #994 from mole99/sdf-interconnect-vector
SDF: Interconnection delays for input/output vectors
This commit is contained in:
commit
7ce068fbdb
|
|
@ -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)
|
||||
|
|
@ -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))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"type" : "normal",
|
||||
"source" : "sdf_interconnect4.v",
|
||||
"iverilog-args" : [ "-Ttyp", "-ginterconnect", "-gspecify" ],
|
||||
"gold" : "sdf_interconnect4"
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
156
vpi/sdf_parse.y
156
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;
|
||||
}
|
||||
;
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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*);
|
||||
|
|
|
|||
|
|
@ -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_;
|
||||
|
|
|
|||
113
vvp/vpi_priv.cc
113
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
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 :
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue