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_interconnect1 vvp_tests/sdf_interconnect1.json
|
||||||
sdf_interconnect2 vvp_tests/sdf_interconnect2.json
|
sdf_interconnect2 vvp_tests/sdf_interconnect2.json
|
||||||
sdf_interconnect3 vvp_tests/sdf_interconnect3.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);
|
assert(vpip_routines);
|
||||||
return vpip_routines->free_object(ref);
|
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)
|
PLI_INT32 vpi_get_vlog_info(p_vpi_vlog_info info)
|
||||||
{
|
{
|
||||||
assert(vpip_routines);
|
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 sdf_header_list cell_list ')'
|
||||||
| '(' K_DELAYFILE error ')'
|
| '(' K_DELAYFILE error ')'
|
||||||
{ vpi_printf("SDF ERROR: %s:%d: Invalid DELAYFILE format\n",
|
{ 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
|
sdfversion
|
||||||
: '(' K_SDFVERSION QSTRING ')'
|
: '(' K_SDFVERSION QSTRING ')'
|
||||||
{ if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Version: %s\n",
|
{ if (sdf_flag_inform) {
|
||||||
sdf_parse_path, @2.first_line, $3);
|
vpi_printf("SDF INFO: %s:%d: Version: %s\n",
|
||||||
free($3);
|
sdf_parse_path, @2.first_line, $3);
|
||||||
|
}
|
||||||
|
free($3);
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
design_name
|
design_name
|
||||||
: '(' K_DESIGN QSTRING ')'
|
: '(' K_DESIGN QSTRING ')'
|
||||||
{ if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Design: %s\n",
|
{ if (sdf_flag_inform) {
|
||||||
sdf_parse_path, @2.first_line, $3);
|
vpi_printf("SDF INFO: %s:%d: Design: %s\n",
|
||||||
free($3);
|
sdf_parse_path, @2.first_line, $3);
|
||||||
|
}
|
||||||
|
free($3);
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
date
|
date
|
||||||
: '(' K_DATE QSTRING ')'
|
: '(' K_DATE QSTRING ')'
|
||||||
{ if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Date: %s\n",
|
{ if (sdf_flag_inform) {
|
||||||
sdf_parse_path, @2.first_line, $3);
|
vpi_printf("SDF INFO: %s:%d: Date: %s\n",
|
||||||
free($3);
|
sdf_parse_path, @2.first_line, $3);
|
||||||
|
}
|
||||||
|
free($3);
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
vendor
|
vendor
|
||||||
: '(' K_VENDOR QSTRING ')'
|
: '(' K_VENDOR QSTRING ')'
|
||||||
{ if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Vendor: %s\n",
|
{ if (sdf_flag_inform) {
|
||||||
sdf_parse_path, @2.first_line, $3);
|
vpi_printf("SDF INFO: %s:%d: Vendor: %s\n",
|
||||||
free($3);
|
sdf_parse_path, @2.first_line, $3);
|
||||||
|
}
|
||||||
|
free($3);
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
program_name
|
program_name
|
||||||
: '(' K_PROGRAM QSTRING ')'
|
: '(' K_PROGRAM QSTRING ')'
|
||||||
{ if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Program: %s\n",
|
{ if (sdf_flag_inform) {
|
||||||
sdf_parse_path, @2.first_line, $3);
|
vpi_printf("SDF INFO: %s:%d: Program: %s\n",
|
||||||
free($3);
|
sdf_parse_path, @2.first_line, $3);
|
||||||
|
}
|
||||||
|
free($3);
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
program_version
|
program_version
|
||||||
: '(' K_VERSION QSTRING ')'
|
: '(' K_VERSION QSTRING ')'
|
||||||
{ if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Program Version: %s\n",
|
{ if (sdf_flag_inform) {
|
||||||
sdf_parse_path, @2.first_line, $3);
|
vpi_printf("SDF INFO: %s:%d: Program Version: %s\n",
|
||||||
|
sdf_parse_path, @2.first_line, $3);
|
||||||
|
}
|
||||||
free($3);
|
free($3);
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
@ -160,42 +172,42 @@ program_version
|
||||||
hierarchy_divider
|
hierarchy_divider
|
||||||
: '(' K_DIVIDER '.' ')'
|
: '(' K_DIVIDER '.' ')'
|
||||||
{ sdf_use_hchar = '.';
|
{ sdf_use_hchar = '.';
|
||||||
if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Divider: \"%c\"\n",
|
if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Divider: \"%c\"\n",
|
||||||
sdf_parse_path, @1.first_line, sdf_use_hchar);
|
sdf_parse_path, @1.first_line, sdf_use_hchar);
|
||||||
}
|
}
|
||||||
| '(' K_DIVIDER '/' ')'
|
| '(' K_DIVIDER '/' ')'
|
||||||
{ sdf_use_hchar = '/';
|
{ sdf_use_hchar = '/';
|
||||||
if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Divider: \"%c\"\n",
|
if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Divider: \"%c\"\n",
|
||||||
sdf_parse_path, @1.first_line, sdf_use_hchar);
|
sdf_parse_path, @1.first_line, sdf_use_hchar);
|
||||||
}
|
}
|
||||||
| '(' K_DIVIDER HCHAR ')'
|
| '(' K_DIVIDER HCHAR ')'
|
||||||
{ /* sdf_use_hchar no-change */
|
{ /* sdf_use_hchar no-change */
|
||||||
if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Divider: \"%c\"\n",
|
if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Divider: \"%c\"\n",
|
||||||
sdf_parse_path, @1.first_line, sdf_use_hchar);
|
sdf_parse_path, @1.first_line, sdf_use_hchar);
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
voltage
|
voltage
|
||||||
: '(' K_VOLTAGE rtriple ')'
|
: '(' K_VOLTAGE rtriple ')'
|
||||||
{ /* The value must be defined. */
|
{ /* The value must be defined. */
|
||||||
if (! $3.defined) {
|
if (! $3.defined) {
|
||||||
vpi_printf("SDF ERROR: %s:%d: Chosen value not defined.\n",
|
vpi_printf("SDF ERROR: %s:%d: Chosen value not defined.\n",
|
||||||
sdf_parse_path, @1.first_line);
|
sdf_parse_path, @1.first_line);
|
||||||
} else if (sdf_flag_inform) {
|
} else if (sdf_flag_inform) {
|
||||||
vpi_printf("SDF INFO: %s:%d: Voltage: %f\n",
|
vpi_printf("SDF INFO: %s:%d: Voltage: %f\n",
|
||||||
sdf_parse_path, @2.first_line, $3.value);
|
sdf_parse_path, @2.first_line, $3.value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
| '(' K_VOLTAGE signed_real_number ')'
|
| '(' K_VOLTAGE signed_real_number ')'
|
||||||
{ if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Voltage: %f\n",
|
{ 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
|
process
|
||||||
: '(' K_PROCESS QSTRING ')'
|
: '(' K_PROCESS QSTRING ')'
|
||||||
{ if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Process: %s\n",
|
{ 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);
|
free($3);
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
@ -203,26 +215,31 @@ process
|
||||||
temperature
|
temperature
|
||||||
: '(' K_TEMPERATURE rtriple ')'
|
: '(' K_TEMPERATURE rtriple ')'
|
||||||
{ /* The value must be defined. */
|
{ /* The value must be defined. */
|
||||||
if (! $3.defined) vpi_printf("SDF ERROR: %s:%d: Chosen value not defined.\n",
|
if (! $3.defined) {
|
||||||
sdf_parse_path, @1.first_line);
|
vpi_printf("SDF ERROR: %s:%d: Chosen value not defined.\n",
|
||||||
else if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Temperature: %f\n",
|
sdf_parse_path, @1.first_line);
|
||||||
sdf_parse_path, @2.first_line, $3.value);
|
} 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 ')'
|
| '(' K_TEMPERATURE signed_real_number ')'
|
||||||
{ if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Temperature: %f\n",
|
{ if (sdf_flag_inform) {
|
||||||
sdf_parse_path, @2.first_line, $3);
|
vpi_printf("SDF INFO: %s:%d: Temperature: %f\n",
|
||||||
|
sdf_parse_path, @2.first_line, $3);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
time_scale
|
time_scale
|
||||||
: '(' K_TIMESCALE REAL_NUMBER IDENTIFIER ')'
|
: '(' K_TIMESCALE REAL_NUMBER IDENTIFIER ')'
|
||||||
{ if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Timescale: %f%s\n",
|
{ 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);
|
free($4);
|
||||||
}
|
}
|
||||||
| '(' K_TIMESCALE INTEGER IDENTIFIER ')'
|
| '(' K_TIMESCALE INTEGER IDENTIFIER ')'
|
||||||
{ if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Timescale: %lu%s\n",
|
{ 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);
|
free($4);
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
@ -272,13 +289,13 @@ timing_spec
|
||||||
: '(' K_DELAY deltype_list ')'
|
: '(' K_DELAY deltype_list ')'
|
||||||
| '(' K_DELAY error ')'
|
| '(' K_DELAY error ')'
|
||||||
{ vpi_printf("SDF ERROR: %s:%d: Syntax error in CELL DELAY SPEC\n",
|
{ 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 ')'
|
| '(' K_TIMINGCHECK tchk_def_list ')'
|
||||||
{ vpi_printf("SDF WARNING: %s:%d: TIMINGCHECK not supported.\n",
|
{ 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 ')'
|
| '(' K_TIMINGCHECK error ')'
|
||||||
{ vpi_printf("SDF ERROR: %s:%d: Syntax error in TIMINGCHECK SPEC\n",
|
{ 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
|
deltype_list
|
||||||
|
|
@ -293,7 +310,7 @@ deltype
|
||||||
| '(' K_INCREMENT del_def_list ')'
|
| '(' K_INCREMENT del_def_list ')'
|
||||||
| '(' error ')'
|
| '(' error ')'
|
||||||
{ vpi_printf("SDF ERROR: %s:%d: Invalid/malformed delay type\n",
|
{ 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
|
del_def_list
|
||||||
|
|
@ -309,54 +326,51 @@ del_def
|
||||||
}
|
}
|
||||||
| '(' K_IOPATH error ')'
|
| '(' K_IOPATH error ')'
|
||||||
{ vpi_printf("SDF ERROR: %s:%d: Invalid/malformed IOPATH\n",
|
{ 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_COND conditional_port_expr
|
||||||
'(' K_IOPATH port_spec port_instance delval_list ')' ')'
|
'(' K_IOPATH port_spec port_instance delval_list ')' ')'
|
||||||
{ if (sdf_flag_warning) vpi_printf("SDF WARNING: %s:%d: "
|
{ if (sdf_flag_warning) vpi_printf("SDF WARNING: %s:%d: "
|
||||||
"COND not supported.\n",
|
"COND not supported.\n",
|
||||||
sdf_parse_path, @2.first_line);
|
sdf_parse_path, @2.first_line);
|
||||||
free($6.string_val);
|
free($6.string_val);
|
||||||
free($7);
|
free($7);
|
||||||
}
|
}
|
||||||
| '(' K_COND QSTRING conditional_port_expr
|
| '(' K_COND QSTRING conditional_port_expr
|
||||||
'(' K_IOPATH port_spec port_instance delval_list ')' ')'
|
'(' K_IOPATH port_spec port_instance delval_list ')' ')'
|
||||||
{ if (sdf_flag_warning) vpi_printf("SDF WARNING: %s:%d: "
|
{ if (sdf_flag_warning) vpi_printf("SDF WARNING: %s:%d: "
|
||||||
"COND not supported.\n",
|
"COND not supported.\n",
|
||||||
sdf_parse_path, @2.first_line);
|
sdf_parse_path, @2.first_line);
|
||||||
free($3);
|
free($3);
|
||||||
free($7.string_val);
|
free($7.string_val);
|
||||||
free($8);
|
free($8);
|
||||||
}
|
}
|
||||||
| '(' K_COND error ')'
|
| '(' K_COND error ')'
|
||||||
{ vpi_printf("SDF ERROR: %s:%d: Invalid/malformed COND\n",
|
{ 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 ')' ')'
|
| '(' K_CONDELSE '(' K_IOPATH port_spec port_instance delval_list ')' ')'
|
||||||
{ if (sdf_flag_warning) vpi_printf("SDF WARNING: %s:%d: "
|
{ if (sdf_flag_warning) vpi_printf("SDF WARNING: %s:%d: "
|
||||||
"CONDELSE not supported.\n",
|
"CONDELSE not supported.\n",
|
||||||
sdf_parse_path, @2.first_line);
|
sdf_parse_path, @2.first_line);
|
||||||
free($5.string_val);
|
free($5.string_val);
|
||||||
free($6);
|
free($6);
|
||||||
}
|
}
|
||||||
| '(' K_CONDELSE error ')'
|
| '(' K_CONDELSE error ')'
|
||||||
{ vpi_printf("SDF ERROR: %s:%d: Invalid/malformed CONDELSE\n",
|
{ 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_instance port_instance delval_list ')' */
|
||||||
| '(' K_INTERCONNECT port_interconnect port_interconnect delval_list ')'
|
| '(' K_INTERCONNECT port_interconnect port_interconnect delval_list ')'
|
||||||
{
|
{ if (sdf_flag_inform) {
|
||||||
if (sdf_flag_inform) {
|
vpi_printf("SDF INFO: %s:%d: INTERCONNECT with "
|
||||||
vpi_printf("SDF INFO: %s:%d: INTERCONNECT with "
|
"port1 = %s index = %d, port2 = %s index = %d\n",
|
||||||
"port1 = %s index = %d, port2 = %s index = %d\n",
|
sdf_parse_path, @2.first_line, $3.name, $3.index, $4.name, $4.index);
|
||||||
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);
|
||||||
sdf_interconnect_delays($3, $4, &$5, @2.first_line);
|
free($4.name);
|
||||||
|
|
||||||
free($3.name);
|
|
||||||
free($4.name);
|
|
||||||
}
|
}
|
||||||
| '(' K_INTERCONNECT error ')'
|
| '(' K_INTERCONNECT error ')'
|
||||||
{ vpi_printf("SDF ERROR: %s:%d: Invalid/malformed INTERCONNECT\n",
|
{ 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
|
port_interconnect
|
||||||
: hierarchical_identifier
|
: hierarchical_identifier
|
||||||
{
|
{ struct interconnect_port_s tmp = {$1, false, 0};
|
||||||
struct interconnect_port_s tmp = {$1, false, 0};
|
$$ = tmp;
|
||||||
$$ = tmp;
|
|
||||||
}
|
}
|
||||||
| hierarchical_identifier '[' INTEGER ']'
|
| hierarchical_identifier '[' INTEGER ']'
|
||||||
{
|
{ struct interconnect_port_s tmp = {$1, true, $3};
|
||||||
struct interconnect_port_s tmp = {$1, true, $3};
|
$$ = tmp;
|
||||||
$$ = 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 port1_handle = get_port_handle(port1.name, sdf_lineno);
|
||||||
vpiHandle port2_handle = get_port_handle(port2.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) {
|
if (port1_handle && port2_handle) {
|
||||||
// Get interModPath for the two ports
|
// Get interModPath for the two ports
|
||||||
vpiHandle intermodpath = vpi_handle_multi(vpiInterModPath, port1_handle, port2_handle);
|
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_chk_error(p_vpi_error_info) { return 0; }
|
||||||
PLI_INT32 vpi_compare_objects(vpiHandle, vpiHandle) { return 0; }
|
PLI_INT32 vpi_compare_objects(vpiHandle, vpiHandle) { return 0; }
|
||||||
PLI_INT32 vpi_free_object(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)
|
PLI_INT32 vpi_get_vlog_info(p_vpi_vlog_info info)
|
||||||
{
|
{
|
||||||
info->argc = 0;
|
info->argc = 0;
|
||||||
|
|
|
||||||
|
|
@ -292,6 +292,7 @@ typedef struct t_vpi_delay {
|
||||||
#define vpiPartSelect 42
|
#define vpiPartSelect 42
|
||||||
#define vpiPathTerm 43
|
#define vpiPathTerm 43
|
||||||
#define vpiPort 44
|
#define vpiPort 44
|
||||||
|
#define vpiPortBit 45
|
||||||
#define vpiRealVar 47
|
#define vpiRealVar 47
|
||||||
#define vpiReg 48
|
#define vpiReg 48
|
||||||
#define vpiRegBit 49
|
#define vpiRegBit 49
|
||||||
|
|
@ -309,6 +310,7 @@ typedef struct t_vpi_delay {
|
||||||
#define vpiScope 84
|
#define vpiScope 84
|
||||||
#define vpiSysTfCall 85
|
#define vpiSysTfCall 85
|
||||||
#define vpiArgument 89
|
#define vpiArgument 89
|
||||||
|
#define vpiBit 90
|
||||||
#define vpiInternalScope 92
|
#define vpiInternalScope 92
|
||||||
#define vpiModPathIn 95
|
#define vpiModPathIn 95
|
||||||
#define vpiModPathOut 96
|
#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);
|
p_vpi_time when, PLI_INT32 flags);
|
||||||
|
|
||||||
extern PLI_INT32 vpi_free_object(vpiHandle ref);
|
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);
|
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 (*chk_error)(p_vpi_error_info);
|
||||||
PLI_INT32 (*compare_objects)(vpiHandle, vpiHandle);
|
PLI_INT32 (*compare_objects)(vpiHandle, vpiHandle);
|
||||||
PLI_INT32 (*free_object)(vpiHandle);
|
PLI_INT32 (*free_object)(vpiHandle);
|
||||||
|
PLI_INT32 (*release_handle)(vpiHandle);
|
||||||
PLI_INT32 (*get_vlog_info)(p_vpi_vlog_info info) ;
|
PLI_INT32 (*get_vlog_info)(p_vpi_vlog_info info) ;
|
||||||
void (*vcontrol)(PLI_INT32, va_list);
|
void (*vcontrol)(PLI_INT32, va_list);
|
||||||
PLI_INT32 (*fopen)(const char*, const char*);
|
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 base, unsigned wid);
|
||||||
~vvp_fun_part();
|
~vvp_fun_part();
|
||||||
|
|
||||||
|
unsigned get_base() const { return base_; }
|
||||||
|
unsigned get_wid() const { return wid_; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
unsigned base_;
|
unsigned base_;
|
||||||
unsigned wid_;
|
unsigned wid_;
|
||||||
|
|
|
||||||
113
vvp/vpi_priv.cc
113
vvp/vpi_priv.cc
|
|
@ -22,6 +22,7 @@
|
||||||
# include "vpi_priv.h"
|
# include "vpi_priv.h"
|
||||||
# include "schedule.h"
|
# include "schedule.h"
|
||||||
# include "logic.h"
|
# include "logic.h"
|
||||||
|
# include "part.h"
|
||||||
#ifdef CHECK_WITH_VALGRIND
|
#ifdef CHECK_WITH_VALGRIND
|
||||||
# include "vvp_cleanup.h"
|
# include "vvp_cleanup.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -290,6 +291,14 @@ PLI_INT32 vpi_free_object(vpiHandle ref)
|
||||||
return rtn;
|
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)
|
static int vpip_get_global(int property)
|
||||||
{
|
{
|
||||||
switch (property) {
|
switch (property) {
|
||||||
|
|
@ -1555,6 +1564,36 @@ vpiHandle vpi_handle_by_name(const char *name, vpiHandle scope)
|
||||||
return out;
|
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
|
// Used to get intermodpath for two ports
|
||||||
vpiHandle vpi_handle_multi(PLI_INT32 type,
|
vpiHandle vpi_handle_multi(PLI_INT32 type,
|
||||||
vpiHandle ref1,
|
vpiHandle ref1,
|
||||||
|
|
@ -1571,6 +1610,32 @@ vpiHandle vpi_handle_multi(PLI_INT32 type,
|
||||||
return nullptr;
|
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);
|
vpiPortInfo* port1 = dynamic_cast<vpiPortInfo*>(ref1);
|
||||||
|
|
||||||
if (!port1) {
|
if (!port1) {
|
||||||
|
|
@ -1587,6 +1652,10 @@ vpiHandle vpi_handle_multi(PLI_INT32 type,
|
||||||
return nullptr;
|
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
|
// 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
|
// to port2 because otherwise the non-delayed version of the signal is dumped
|
||||||
// even tho the intermodpath is correctly inserted
|
// 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) {
|
if (port1->get_direction() == vpiOutput && port2->get_direction() == vpiOutput) {
|
||||||
vpiHandle scope_port2 = vpi_handle(vpiScope, ref2);
|
vpiHandle scope_port2 = vpi_handle(vpiScope, ref2);
|
||||||
assert(scope_port2);
|
assert(scope_port2);
|
||||||
std::string port2_name(vpi_get_str(vpiName, ref2));
|
|
||||||
|
|
||||||
// Iterate over nets in the scope of port2
|
// Iterate over nets in the scope of port2
|
||||||
vpiHandle net_i = vpi_iterate(vpiNet, scope_port2) ;
|
vpiHandle net_i = vpi_iterate(vpiNet, scope_port2) ;
|
||||||
|
|
@ -1638,13 +1706,43 @@ vpiHandle vpi_handle_multi(PLI_INT32 type,
|
||||||
return nullptr;
|
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
|
// Iterate over all nodes connected to port1
|
||||||
vvp_net_ptr_t cur = net1->out_;
|
vvp_net_ptr_t cur = net1->out_;
|
||||||
vvp_net_ptr_t prev = vvp_net_ptr_t(nullptr, 0);
|
vvp_net_ptr_t prev = vvp_net_ptr_t(nullptr, 0);
|
||||||
|
|
||||||
while (cur.ptr()) {
|
while (cur.ptr()) {
|
||||||
// Port2 is directly connected to port1
|
// Either port2 is directly connected to port1
|
||||||
if (cur.ptr() == net2) {
|
// 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;
|
vvp_net_t*new_net = new vvp_net_t;
|
||||||
|
|
||||||
// Create new node with intermodpath and connect port2 to it
|
// 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
|
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 both ports are vpiOutput and port2 is not a vector,
|
||||||
if (output_signal) {
|
// we have to reassign the __vpiSignal so that the delayed
|
||||||
|
// values get dumped
|
||||||
|
if (output_signal && !port2_has_index) {
|
||||||
net2->fil = net1->fil;
|
net2->fil = net1->fil;
|
||||||
net1->fil = nullptr;
|
net1->fil = nullptr;
|
||||||
output_signal->node = net2;
|
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, "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;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1908,6 +2010,7 @@ vpip_routines_s vpi_routines = {
|
||||||
.chk_error = vpi_chk_error,
|
.chk_error = vpi_chk_error,
|
||||||
.compare_objects = vpi_compare_objects,
|
.compare_objects = vpi_compare_objects,
|
||||||
.free_object = vpi_free_object,
|
.free_object = vpi_free_object,
|
||||||
|
.release_handle = vpi_release_handle,
|
||||||
.get_vlog_info = vpi_get_vlog_info,
|
.get_vlog_info = vpi_get_vlog_info,
|
||||||
.vcontrol = vpi_sim_vcontrol,
|
.vcontrol = vpi_sim_vcontrol,
|
||||||
.fopen = vpi_fopen,
|
.fopen = vpi_fopen,
|
||||||
|
|
|
||||||
|
|
@ -432,6 +432,7 @@ struct __vpiBit {
|
||||||
int get_index(void) const;
|
int get_index(void) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class vpiPortBitInfo;
|
||||||
|
|
||||||
class vpiPortInfo : public __vpiHandle {
|
class vpiPortInfo : public __vpiHandle {
|
||||||
public:
|
public:
|
||||||
|
|
@ -445,11 +446,17 @@ class vpiPortInfo : public __vpiHandle {
|
||||||
|
|
||||||
int get_type_code(void) const { return vpiPort; }
|
int get_type_code(void) const { return vpiPort; }
|
||||||
int get_direction(void) { return direction_; }
|
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);
|
int vpi_get(int code);
|
||||||
char* vpi_get_str(int code);
|
char* vpi_get_str(int code);
|
||||||
vpiHandle vpi_handle(int code);
|
vpiHandle vpi_handle(int code);
|
||||||
vvp_net_t* get_port(void) const { return ref_; }
|
vvp_net_t* get_port(void) const { return ref_; }
|
||||||
|
vpiHandle vpi_iterate(int code);
|
||||||
|
|
||||||
|
std::vector<vpiPortBitInfo*> port_bits_;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
__vpiScope *parent_;
|
__vpiScope *parent_;
|
||||||
|
|
@ -460,6 +467,23 @@ class vpiPortInfo : public __vpiHandle {
|
||||||
vvp_net_t *ref_;
|
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
|
* This is used by system calls to represent a bit/part select of
|
||||||
* a simple variable or constant array word.
|
* a simple variable or constant array word.
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,7 @@ void vpip_make_root_iterator(__vpiHandle**&table, unsigned&ntable)
|
||||||
|
|
||||||
#ifdef CHECK_WITH_VALGRIND
|
#ifdef CHECK_WITH_VALGRIND
|
||||||
void port_delete(__vpiHandle*handle);
|
void port_delete(__vpiHandle*handle);
|
||||||
|
void port_bit_delete(__vpiHandle*handle);
|
||||||
|
|
||||||
/* Class definitions need to be cleaned up at the end. */
|
/* Class definitions need to be cleaned up at the end. */
|
||||||
static class_type **class_list = 0;
|
static class_type **class_list = 0;
|
||||||
|
|
@ -110,6 +111,9 @@ static void delete_sub_scopes(__vpiScope *scope)
|
||||||
case vpiPort:
|
case vpiPort:
|
||||||
port_delete(item);
|
port_delete(item);
|
||||||
break;
|
break;
|
||||||
|
case vpiPortBit:
|
||||||
|
port_bit_delete(item);
|
||||||
|
break;
|
||||||
case vpiStringVar:
|
case vpiStringVar:
|
||||||
string_delete(item);
|
string_delete(item);
|
||||||
break;
|
break;
|
||||||
|
|
@ -735,6 +739,74 @@ vpiHandle vpiPortInfo::vpi_handle(int code)
|
||||||
return 0;
|
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
|
/* 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
|
* 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 )
|
void compile_port_info( unsigned index, int vpi_direction, unsigned width, const char *name, char* buffer )
|
||||||
{
|
{
|
||||||
vpiHandle obj = new vpiPortInfo( vpip_peek_current_scope(),
|
vpiPortInfo* obj = new vpiPortInfo( vpip_peek_current_scope(),
|
||||||
index, vpi_direction, width, name, buffer );
|
index, vpi_direction, width, name, buffer );
|
||||||
vpip_attach_to_current_scope(obj);
|
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_put_value
|
||||||
vpi_register_cb
|
vpi_register_cb
|
||||||
vpi_register_systf
|
vpi_register_systf
|
||||||
|
vpi_release_handle
|
||||||
vpi_remove_cb
|
vpi_remove_cb
|
||||||
vpi_scan
|
vpi_scan
|
||||||
vpi_sim_control
|
vpi_sim_control
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue