Merge pull request #973 from mole99/sdf-interconnect
Implement SDF INTERCONNECT
This commit is contained in:
commit
8e0fa024d0
|
|
@ -177,6 +177,11 @@ extern bool gn_icarus_misc_flag;
|
|||
is false, then skip elaboration of specify behavior. */
|
||||
extern bool gn_specify_blocks_flag;
|
||||
|
||||
/* If this flag is true, then add input/output buffers to modules so that
|
||||
VVP can insert intermodpaths inbetween. If this flag
|
||||
is false, then no input/output buffers are inserted if not needed. */
|
||||
extern bool gn_interconnect_flag;
|
||||
|
||||
/* If this flag is true, then elaborate supported assertion statements. If
|
||||
this flag is false, then stub out supported assertion statements. */
|
||||
extern bool gn_supported_assertions_flag;
|
||||
|
|
|
|||
|
|
@ -95,6 +95,14 @@ simulation, and in fact can hurt performance of the
|
|||
simulation. However, disabling specify blocks reduces accuracy of
|
||||
full-timing simulations.
|
||||
.TP 8
|
||||
.B -ginterconnect\fI|\fP-gno-interconnect
|
||||
Enable or disable (default) SDF interconnect support. When enabled,
|
||||
input and output buffers will be added to modules, so that VVP can
|
||||
add interconnection delays. This option is commonly not needed for RTL
|
||||
simulation, and in fact can hurt performance of the
|
||||
simulation. However, disabling interconnection delays reduces accuracy of
|
||||
full-timing simulations.
|
||||
.TP 8
|
||||
.B -gstd-include\fI|\fP-gno-std-include
|
||||
Enable (default) or disable the search of a standard installation
|
||||
include directory after all other explicit include directories. This
|
||||
|
|
|
|||
|
|
@ -125,6 +125,7 @@ char depmode = 'a';
|
|||
|
||||
const char*generation = "2005";
|
||||
const char*gen_specify = "no-specify";
|
||||
const char*gen_interconnect = "no-interconnect";
|
||||
const char*gen_assertions = "assertions";
|
||||
const char*gen_xtypes = "xtypes";
|
||||
const char*gen_icarus = "icarus-misc";
|
||||
|
|
@ -757,6 +758,12 @@ static int process_generation(const char*name)
|
|||
else if (strcmp(name,"no-specify") == 0)
|
||||
gen_specify = "no-specify";
|
||||
|
||||
else if (strcmp(name,"interconnect") == 0)
|
||||
gen_interconnect = "interconnect";
|
||||
|
||||
else if (strcmp(name,"no-interconnect") == 0)
|
||||
gen_interconnect = "no-interconnect";
|
||||
|
||||
else if (strcmp(name,"assertions") == 0)
|
||||
gen_assertions = "assertions";
|
||||
|
||||
|
|
@ -821,6 +828,7 @@ static int process_generation(const char*name)
|
|||
"Other generation flags:\n"
|
||||
" assertions | supported-assertions | no-assertions\n"
|
||||
" specify | no-specify\n"
|
||||
" interconnect | no-interconnect\n"
|
||||
" verilog-ams | no-verilog-ams\n"
|
||||
" std-include | no-std-include\n"
|
||||
" relative-include | no-relative-include\n"
|
||||
|
|
@ -1368,6 +1376,7 @@ int main(int argc, char **argv)
|
|||
if (mtm != 0) fprintf(iconfig_file, "-T:%s\n", mtm);
|
||||
fprintf(iconfig_file, "generation:%s\n", generation);
|
||||
fprintf(iconfig_file, "generation:%s\n", gen_specify);
|
||||
fprintf(iconfig_file, "generation:%s\n", gen_interconnect);
|
||||
fprintf(iconfig_file, "generation:%s\n", gen_assertions);
|
||||
fprintf(iconfig_file, "generation:%s\n", gen_xtypes);
|
||||
fprintf(iconfig_file, "generation:%s\n", gen_io_range_error);
|
||||
|
|
|
|||
37
elaborate.cc
37
elaborate.cc
|
|
@ -1159,13 +1159,13 @@ static void convert_net(Design*des, const LineInfo *line,
|
|||
}
|
||||
|
||||
static void isolate_and_connect(Design*des, NetScope*scope, const PGModule*mod,
|
||||
NetNet*port, NetNet*sig, NetNet::PortType ptype)
|
||||
NetNet*port, NetNet*sig, NetNet::PortType ptype, int idx = -1)
|
||||
{
|
||||
switch (ptype) {
|
||||
case NetNet::POUTPUT:
|
||||
{
|
||||
NetBUFZ*tmp = new NetBUFZ(scope, scope->local_symbol(),
|
||||
sig->vector_width(), true);
|
||||
sig->vector_width(), true, idx);
|
||||
tmp->set_line(*mod);
|
||||
des->add_node(tmp);
|
||||
connect(tmp->pin(1), port->pin(0));
|
||||
|
|
@ -1598,17 +1598,21 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
|
|||
}
|
||||
}
|
||||
|
||||
if (need_bufz_for_input_port(prts)) {
|
||||
NetBUFZ*tmp = new NetBUFZ(scope, scope->local_symbol(),
|
||||
sig->vector_width(), true);
|
||||
// Add module input buffers if needed
|
||||
if (need_bufz_for_input_port(prts) || gn_interconnect_flag == true) {
|
||||
// FIXME improve this for multiple module instances
|
||||
NetScope* inner_scope = scope->instance_arrays[get_name()][0];
|
||||
|
||||
NetBUFZ*tmp = new NetBUFZ(inner_scope, inner_scope->local_symbol(),
|
||||
sig->vector_width(), true, gn_interconnect_flag ? idx : -1);
|
||||
tmp->set_line(*this);
|
||||
des->add_node(tmp);
|
||||
connect(tmp->pin(1), sig->pin(0));
|
||||
|
||||
netvector_t*tmp2_vec = new netvector_t(sig->data_type(),
|
||||
sig->vector_width()-1,0);
|
||||
NetNet*tmp2 = new NetNet(scope, scope->local_symbol(),
|
||||
NetNet::WIRE, tmp2_vec);
|
||||
sig->vector_width()-1,0);
|
||||
NetNet*tmp2 = new NetNet(inner_scope, inner_scope->local_symbol(),
|
||||
NetNet::WIRE, tmp2_vec);
|
||||
tmp2->local_flag(true);
|
||||
tmp2->set_line(*this);
|
||||
connect(tmp->pin(0), tmp2->pin(0));
|
||||
|
|
@ -1933,8 +1937,11 @@ void PGModule::elaborate_mod_(Design*des, Module*rmod, NetScope*scope) const
|
|||
// that are a delay path destination, to avoid
|
||||
// the delay being applied to other drivers of
|
||||
// the external signal.
|
||||
if (prts[0]->delay_paths() > 0) {
|
||||
isolate_and_connect(des, scope, this, prts[0], sig, ptype);
|
||||
if (prts[0]->delay_paths() > 0 || (gn_interconnect_flag == true && ptype == NetNet::POUTPUT)) {
|
||||
// FIXME improve this for multiple module instances
|
||||
NetScope* inner_scope = scope->instance_arrays[get_name()][0];
|
||||
|
||||
isolate_and_connect(des, inner_scope, this, prts[0], sig, ptype, gn_interconnect_flag ? idx : -1);
|
||||
} else {
|
||||
connect(prts[0]->pin(0), sig->pin(0));
|
||||
}
|
||||
|
|
@ -3496,14 +3503,14 @@ NetProc* PCallTask::elaborate_sys(Design*des, NetScope*scope) const
|
|||
parm.parm);
|
||||
}
|
||||
|
||||
// Special case: Specify blocks are turned off, and this is an
|
||||
// $sdf_annotate system task. There will be nothing for $sdf
|
||||
// to annotate, and the user is intending to turn the behavior
|
||||
// Special case: Specify blocks and interconnects are turned off,
|
||||
// and this is an $sdf_annotate system task. There will be nothing for
|
||||
// $sdf to annotate, and the user is intending to turn the behavior
|
||||
// off anyhow, so replace the system task invocation with a no-op.
|
||||
if (gn_specify_blocks_flag == false && name == "$sdf_annotate") {
|
||||
if (gn_specify_blocks_flag == false && gn_interconnect_flag == false && name == "$sdf_annotate") {
|
||||
|
||||
cerr << get_fileline() << ": warning: Omitting $sdf_annotate() "
|
||||
<< "since specify blocks are being omitted." << endl;
|
||||
<< "since specify blocks and interconnects are being omitted." << endl;
|
||||
NetBlock*noop = new NetBlock(NetBlock::SEQU, scope);
|
||||
noop->set_line(*this);
|
||||
return noop;
|
||||
|
|
|
|||
2
ivl.def
2
ivl.def
|
|
@ -109,6 +109,7 @@ ivl_logic_scope
|
|||
ivl_logic_type
|
||||
ivl_logic_udp
|
||||
ivl_logic_width
|
||||
ivl_logic_port_buffer
|
||||
|
||||
ivl_lpm_array
|
||||
ivl_lpm_aset_value
|
||||
|
|
@ -229,6 +230,7 @@ ivl_scope_mod_module_ports
|
|||
ivl_scope_mod_module_port_name
|
||||
ivl_scope_mod_module_port_type
|
||||
ivl_scope_mod_module_port_width
|
||||
ivl_scope_mod_module_port_buffer
|
||||
ivl_scope_mod_port
|
||||
ivl_scope_name
|
||||
ivl_scope_param
|
||||
|
|
|
|||
|
|
@ -1112,6 +1112,7 @@ extern ivl_drive_t ivl_logic_drive0(ivl_net_logic_t net);
|
|||
extern ivl_drive_t ivl_logic_drive1(ivl_net_logic_t net);
|
||||
extern unsigned ivl_logic_width(ivl_net_logic_t net);
|
||||
extern unsigned ivl_logic_is_cassign(ivl_net_logic_t net);
|
||||
extern unsigned ivl_logic_port_buffer(ivl_net_logic_t net);
|
||||
|
||||
/* DEPRECATED */
|
||||
extern const char* ivl_logic_attr(ivl_net_logic_t net, const char*key);
|
||||
|
|
@ -1897,6 +1898,7 @@ extern unsigned ivl_scope_mod_module_ports(ivl_scope_t net);
|
|||
extern const char *ivl_scope_mod_module_port_name(ivl_scope_t net, unsigned idx );
|
||||
extern ivl_signal_port_t ivl_scope_mod_module_port_type(ivl_scope_t net, unsigned idx );
|
||||
extern unsigned ivl_scope_mod_module_port_width(ivl_scope_t net, unsigned idx );
|
||||
extern ivl_net_logic_t ivl_scope_mod_module_port_buffer(ivl_scope_t net, unsigned idx );
|
||||
|
||||
extern unsigned ivl_scope_ports(ivl_scope_t net);
|
||||
extern ivl_signal_t ivl_scope_port(ivl_scope_t net, unsigned idx);
|
||||
|
|
@ -2432,3 +2434,4 @@ _END_DECL
|
|||
#undef ENUM_UNSIGNED_INT
|
||||
|
||||
#endif /* IVL_ivl_target_H */
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
SDF WARNING: ivltests/br_gh889.sdf:18: loaded from vlog95.v:17: Wildcard cell instance specification (*) currently not supported.
|
||||
0 A=x, B=x, Q=x
|
||||
10 A=1, B=1, Q=x
|
||||
11 A=1, B=1, Q=0
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
SDF WARNING: ivltests/br_gh889.sdf:18: loaded from ./ivltests/br_gh889.v:21: Wildcard cell instance specification (*) currently not supported.
|
||||
0 A=x, B=x, Q=x
|
||||
10 A=1, B=1, Q=x
|
||||
11 A=1, B=1, Q=0
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
SDF INFO: Loading ivltests/sdf_header.sdf from ivltests/sdf_header.v:6
|
||||
SDF INFO: ivltests/sdf_header.sdf:2: Version: 3.0
|
||||
SDF INFO: ivltests/sdf_header.sdf:3: Design: test
|
||||
SDF INFO: ivltests/sdf_header.sdf:4: Date: Wed Mar 8 12:34:56 2023
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
time=0 a=x b=x
|
||||
time=5000 a=0 b=x
|
||||
time=5680 a=0 b=0
|
||||
time=15000 a=1 b=0
|
||||
time=15680 a=1 b=1
|
||||
ivltests/sdf_interconnect1.v:59: $finish called at 25000 (1ps)
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
time=0 a=x b=x
|
||||
time=5000 a=0 b=x
|
||||
time=5110 a=0 b=0
|
||||
time=15000 a=1 b=0
|
||||
time=15330 a=1 b=1
|
||||
ivltests/sdf_interconnect2.v:61: $finish called at 25000 (1ps)
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
time=0 a=x b=x c=x d=x
|
||||
time=10000 a=0 b=0 c=0 d=x
|
||||
time=10560 a=0 b=0 c=0 d=0
|
||||
time=20000 a=1 b=0 c=0 d=0
|
||||
time=20560 a=1 b=0 c=0 d=1
|
||||
time=30000 a=0 b=1 c=0 d=1
|
||||
time=30450 a=0 b=1 c=0 d=0
|
||||
time=40000 a=1 b=1 c=0 d=0
|
||||
time=40560 a=1 b=1 c=0 d=1
|
||||
time=50000 a=0 b=0 c=1 d=1
|
||||
time=50340 a=0 b=0 c=1 d=0
|
||||
time=50450 a=0 b=0 c=1 d=1
|
||||
time=50560 a=0 b=0 c=1 d=0
|
||||
time=60000 a=1 b=0 c=1 d=0
|
||||
time=60560 a=1 b=0 c=1 d=1
|
||||
time=70000 a=0 b=1 c=1 d=1
|
||||
time=70450 a=0 b=1 c=1 d=0
|
||||
time=80000 a=1 b=1 c=1 d=0
|
||||
time=80560 a=1 b=1 c=1 d=1
|
||||
ivltests/sdf_interconnect3.v:132: $finish called at 90000 (1ps)
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
(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 buffer0.in (0.010:0.020:0.030) (0.010:0.020:0.030))
|
||||
(INTERCONNECT buffer0.out buffer1.in (0.010:0.020:0.030) (0.010:0.020:0.030))
|
||||
(INTERCONNECT buffer1.out buffer2.in (0.010:0.020:0.030) (0.010:0.020:0.030))
|
||||
(INTERCONNECT buffer2.out b (0.010:0.020:0.030) (0.010:0.020:0.030))
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
(CELL
|
||||
(CELLTYPE "buffer")
|
||||
(INSTANCE buffer0)
|
||||
(DELAY
|
||||
(ABSOLUTE
|
||||
(IOPATH in out (0.1:0.2:0.3) (0.1:0.2:0.3))
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
(CELL
|
||||
(CELLTYPE "buffer")
|
||||
(INSTANCE buffer1)
|
||||
(DELAY
|
||||
(ABSOLUTE
|
||||
(IOPATH in out (0.1:0.2:0.3) (0.1:0.2:0.3))
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
(CELL
|
||||
(CELLTYPE "buffer")
|
||||
(INSTANCE buffer2)
|
||||
(DELAY
|
||||
(ABSOLUTE
|
||||
(IOPATH in out (0.1:0.2:0.3) (0.1:0.2:0.3))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
`timescale 1ns/1ps
|
||||
|
||||
/*
|
||||
This design tests the interconnection delay
|
||||
for three buffers in series
|
||||
*/
|
||||
|
||||
module buffer (
|
||||
input in,
|
||||
output out
|
||||
);
|
||||
specify
|
||||
(in => out) = (0.0:0.0:0.0);
|
||||
endspecify
|
||||
|
||||
assign out = in;
|
||||
|
||||
endmodule
|
||||
|
||||
module my_design (
|
||||
input a,
|
||||
output b
|
||||
);
|
||||
wire w1, w2;
|
||||
|
||||
buffer buffer0 (
|
||||
.in (a),
|
||||
.out (w1)
|
||||
);
|
||||
|
||||
buffer buffer1 (
|
||||
.in (w1),
|
||||
.out (w2)
|
||||
);
|
||||
|
||||
buffer buffer2 (
|
||||
.in (w2),
|
||||
.out (b)
|
||||
);
|
||||
|
||||
endmodule
|
||||
|
||||
module top;
|
||||
|
||||
initial begin
|
||||
$sdf_annotate("ivltests/sdf_interconnect1.sdf", my_design_inst);
|
||||
$monitor("time=%0t a=%h b=%h", $realtime, a, b);
|
||||
end
|
||||
|
||||
reg a;
|
||||
wire b;
|
||||
|
||||
initial begin
|
||||
#5;
|
||||
a <= 1'b0;
|
||||
#10;
|
||||
a <= 1'b1;
|
||||
#10;
|
||||
$finish;
|
||||
end
|
||||
|
||||
my_design my_design_inst (
|
||||
.a (a),
|
||||
.b (b)
|
||||
);
|
||||
|
||||
endmodule
|
||||
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
(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 buffer0.in (0.000:0.010:0.000) (0.000:0.010:0.000))
|
||||
(INTERCONNECT a buffer1.in (0.000:0.020:0.000) (0.000:0.020:0.000))
|
||||
(INTERCONNECT a buffer2.in (0.000:0.030:0.000) (0.000:0.030:0.000))
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
(CELL
|
||||
(CELLTYPE "buffer")
|
||||
(INSTANCE buffer0)
|
||||
(DELAY
|
||||
(ABSOLUTE
|
||||
(IOPATH in out (0.000:0.100:0.000) (0.000:0.100:0.000))
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
(CELL
|
||||
(CELLTYPE "buffer")
|
||||
(INSTANCE buffer1)
|
||||
(DELAY
|
||||
(ABSOLUTE
|
||||
(IOPATH in out (0.000:0.200:0.000) (0.000:0.200:0.000))
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
(CELL
|
||||
(CELLTYPE "buffer")
|
||||
(INSTANCE buffer2)
|
||||
(DELAY
|
||||
(ABSOLUTE
|
||||
(IOPATH in out (0.000:0.300:0.000) (0.000:0.300:0.000))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
`timescale 1ns/1ps
|
||||
|
||||
/*
|
||||
This design tests the interconnection delay
|
||||
for three buffers in parallel
|
||||
*/
|
||||
|
||||
module buffer (
|
||||
input in,
|
||||
output out
|
||||
);
|
||||
specify
|
||||
(in => out) = (0.0:0.0:0.0);
|
||||
endspecify
|
||||
|
||||
assign out = in;
|
||||
|
||||
endmodule
|
||||
|
||||
module my_design (
|
||||
input a,
|
||||
output b
|
||||
);
|
||||
wire w1, w2, w3;
|
||||
|
||||
buffer buffer0 (
|
||||
.in (a),
|
||||
.out (w1)
|
||||
);
|
||||
|
||||
buffer buffer1 (
|
||||
.in (a),
|
||||
.out (w2)
|
||||
);
|
||||
|
||||
buffer buffer2 (
|
||||
.in (a),
|
||||
.out (w3)
|
||||
);
|
||||
|
||||
assign b = w1 & w2 & w3;
|
||||
|
||||
endmodule
|
||||
|
||||
module top;
|
||||
|
||||
initial begin
|
||||
$sdf_annotate("ivltests/sdf_interconnect2.sdf", my_design_inst);
|
||||
$monitor("time=%0t a=%h b=%h", $realtime, a, b);
|
||||
end
|
||||
|
||||
reg a;
|
||||
wire b;
|
||||
|
||||
initial begin
|
||||
#5;
|
||||
a <= 1'b0;
|
||||
#10;
|
||||
a <= 1'b1;
|
||||
#10;
|
||||
$finish;
|
||||
end
|
||||
|
||||
my_design my_design_inst (
|
||||
.a (a),
|
||||
.b (b)
|
||||
);
|
||||
|
||||
endmodule
|
||||
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
(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 buffer0.in (0.000:0.010:0.000) (0.000:0.010:0.000))
|
||||
(INTERCONNECT b my_xor0.a (0.000:0.010:0.000) (0.000:0.010:0.000))
|
||||
(INTERCONNECT c my_xor0.b (0.000:0.010:0.000) (0.000:0.010:0.000))
|
||||
(INTERCONNECT buffer0.out my_xor1.a (0.000:0.010:0.000) (0.000:0.010:0.000))
|
||||
(INTERCONNECT b my_xor1.b (0.000:0.010:0.000) (0.000:0.010:0.000))
|
||||
(INTERCONNECT my_xor0.out buffer1.in (0.000:0.010:0.000) (0.000:0.010:0.000))
|
||||
(INTERCONNECT my_xor1.out my_xor2.a (0.000:0.010:0.000) (0.000:0.010:0.000))
|
||||
(INTERCONNECT buffer1.out my_xor2.b (0.000:0.010:0.000) (0.000:0.010:0.000))
|
||||
(INTERCONNECT c buffer2.in (0.000:0.010:0.000) (0.000:0.010:0.000))
|
||||
(INTERCONNECT my_xor2.out my_xor3.a (0.000:0.010:0.000) (0.000:0.010:0.000))
|
||||
(INTERCONNECT buffer2.out my_xor3.b (0.000:0.010:0.000) (0.000:0.010:0.000))
|
||||
(INTERCONNECT my_xor3.out buffer3.in (0.000:0.010:0.000) (0.000:0.010:0.000))
|
||||
(INTERCONNECT buffer3.out d (0.000:0.010:0.000) (0.000:0.010: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))
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
(CELL
|
||||
(CELLTYPE "buffer")
|
||||
(INSTANCE buffer3)
|
||||
(DELAY
|
||||
(ABSOLUTE
|
||||
(IOPATH in out (0.0:0.1:0.0) (0.0:0.1:0.0))
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
(CELL
|
||||
(CELLTYPE "my_xor")
|
||||
(INSTANCE my_xor0)
|
||||
(DELAY
|
||||
(ABSOLUTE
|
||||
(IOPATH a out (0.0:0.1:0.0) (0.0:0.1:0.0))
|
||||
(IOPATH b out (0.0:0.1:0.0) (0.0:0.1:0.0))
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
(CELL
|
||||
(CELLTYPE "my_xor")
|
||||
(INSTANCE my_xor1)
|
||||
(DELAY
|
||||
(ABSOLUTE
|
||||
(IOPATH a out (0.0:0.1:0.0) (0.0:0.1:0.0))
|
||||
(IOPATH b out (0.0:0.1:0.0) (0.0:0.1:0.0))
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
(CELL
|
||||
(CELLTYPE "my_xor")
|
||||
(INSTANCE my_xor2)
|
||||
(DELAY
|
||||
(ABSOLUTE
|
||||
(IOPATH a out (0.0:0.1:0.0) (0.0:0.1:0.0))
|
||||
(IOPATH b out (0.0:0.1:0.0) (0.0:0.1:0.0))
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
(CELL
|
||||
(CELLTYPE "my_xor")
|
||||
(INSTANCE my_xor3)
|
||||
(DELAY
|
||||
(ABSOLUTE
|
||||
(IOPATH a out (0.0:0.1:0.0) (0.0:0.1:0.0))
|
||||
(IOPATH b out (0.0:0.1:0.0) (0.0:0.1:0.0))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
|
@ -0,0 +1,143 @@
|
|||
`timescale 1ns/1ps
|
||||
|
||||
/*
|
||||
This design tests the interconnection delays
|
||||
for a circuit of various buffers and xors
|
||||
*/
|
||||
|
||||
module my_xor (
|
||||
input a,
|
||||
input b,
|
||||
output out
|
||||
);
|
||||
specify
|
||||
(a => out) = (0.0:0.0:0.0);
|
||||
(b => out) = (0.0:0.0:0.0);
|
||||
endspecify
|
||||
|
||||
assign out = a ^ b;
|
||||
|
||||
endmodule
|
||||
|
||||
module buffer (
|
||||
input in,
|
||||
output out
|
||||
);
|
||||
specify
|
||||
(in => out) = (0.0:0.0:0.0);
|
||||
endspecify
|
||||
|
||||
assign out = in;
|
||||
|
||||
endmodule
|
||||
|
||||
module my_design (
|
||||
input a,
|
||||
input b,
|
||||
input c,
|
||||
output d
|
||||
);
|
||||
wire w1, w2, w3, w4, w5, w6, w7;
|
||||
|
||||
buffer buffer0 (
|
||||
.in (a),
|
||||
.out (w1)
|
||||
);
|
||||
|
||||
my_xor my_xor0 (
|
||||
.a (b),
|
||||
.b (c),
|
||||
.out (w2)
|
||||
);
|
||||
|
||||
my_xor my_xor1 (
|
||||
.a (w1),
|
||||
.b (b),
|
||||
.out (w3)
|
||||
);
|
||||
|
||||
buffer buffer1 (
|
||||
.in (w2),
|
||||
.out (w4)
|
||||
);
|
||||
|
||||
my_xor my_xor2 (
|
||||
.a (w3),
|
||||
.b (w4),
|
||||
.out (w5)
|
||||
);
|
||||
|
||||
buffer buffer2 (
|
||||
.in (c),
|
||||
.out (w6)
|
||||
);
|
||||
|
||||
my_xor my_xor3 (
|
||||
.a (w5),
|
||||
.b (w6),
|
||||
.out (w7)
|
||||
);
|
||||
|
||||
buffer buffer3 (
|
||||
.in (w7),
|
||||
.out (d)
|
||||
);
|
||||
|
||||
endmodule
|
||||
|
||||
module top;
|
||||
|
||||
initial begin
|
||||
$sdf_annotate("ivltests/sdf_interconnect3.sdf", my_design_inst);
|
||||
$monitor("time=%0t a=%h b=%h c=%h d=%h", $realtime, a, b, c, d);
|
||||
end
|
||||
|
||||
reg a, b, c;
|
||||
wire d;
|
||||
|
||||
initial begin
|
||||
#10;
|
||||
a <= 1'b0;
|
||||
b <= 1'b0;
|
||||
c <= 1'b0;
|
||||
#10;
|
||||
a <= 1'b1;
|
||||
b <= 1'b0;
|
||||
c <= 1'b0;
|
||||
#10;
|
||||
a <= 1'b0;
|
||||
b <= 1'b1;
|
||||
c <= 1'b0;
|
||||
#10;
|
||||
a <= 1'b1;
|
||||
b <= 1'b1;
|
||||
c <= 1'b0;
|
||||
#10;
|
||||
a <= 1'b0;
|
||||
b <= 1'b0;
|
||||
c <= 1'b1;
|
||||
#10;
|
||||
a <= 1'b1;
|
||||
b <= 1'b0;
|
||||
c <= 1'b1;
|
||||
#10;
|
||||
a <= 1'b0;
|
||||
b <= 1'b1;
|
||||
c <= 1'b1;
|
||||
#10;
|
||||
a <= 1'b1;
|
||||
b <= 1'b1;
|
||||
c <= 1'b1;
|
||||
#10;
|
||||
$finish;
|
||||
end
|
||||
|
||||
my_design my_design_inst (
|
||||
.a (a),
|
||||
.b (b),
|
||||
.c (c),
|
||||
.d (d)
|
||||
);
|
||||
|
||||
endmodule
|
||||
|
||||
|
|
@ -94,3 +94,6 @@ task_return_fail1 vvp_tests/task_return_fail1.json
|
|||
task_return_fail2 vvp_tests/task_return_fail2.json
|
||||
timing_check_syntax vvp_tests/timing_check_syntax.json
|
||||
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
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"type" : "normal",
|
||||
"source" : "sdf_interconnect1.v",
|
||||
"iverilog-args" : [ "-Ttyp", "-ginterconnect", "-gspecify" ],
|
||||
"gold" : "sdf_interconnect1"
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"type" : "normal",
|
||||
"source" : "sdf_interconnect2.v",
|
||||
"iverilog-args" : [ "-Ttyp", "-ginterconnect", "-gspecify" ],
|
||||
"gold" : "sdf_interconnect2"
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"type" : "normal",
|
||||
"source" : "sdf_interconnect3.v",
|
||||
"iverilog-args" : [ "-Ttyp", "-ginterconnect", "-gspecify" ],
|
||||
"gold" : "sdf_interconnect3"
|
||||
}
|
||||
12
main.cc
12
main.cc
|
|
@ -106,6 +106,7 @@ generation_t generation_flag = GN_DEFAULT;
|
|||
bool gn_icarus_misc_flag = true;
|
||||
bool gn_cadence_types_flag = true;
|
||||
bool gn_specify_blocks_flag = true;
|
||||
bool gn_interconnect_flag = true;
|
||||
bool gn_supported_assertions_flag = true;
|
||||
bool gn_unsupported_assertions_flag = true;
|
||||
bool gn_io_range_error_flag = true;
|
||||
|
|
@ -334,6 +335,12 @@ static void process_generation_flag(const char*gen)
|
|||
} else if (strcmp(gen,"no-specify") == 0) {
|
||||
gn_specify_blocks_flag = false;
|
||||
|
||||
} else if (strcmp(gen,"interconnect") == 0) {
|
||||
gn_interconnect_flag = true;
|
||||
|
||||
} else if (strcmp(gen,"no-interconnect") == 0) {
|
||||
gn_interconnect_flag = false;
|
||||
|
||||
} else if (strcmp(gen,"assertions") == 0) {
|
||||
gn_supported_assertions_flag = true;
|
||||
gn_unsupported_assertions_flag = true;
|
||||
|
|
@ -1095,6 +1102,11 @@ int main(int argc, char*argv[])
|
|||
else
|
||||
cout << ",no-specify";
|
||||
|
||||
if (gn_interconnect_flag)
|
||||
cout << ",interconnect";
|
||||
else
|
||||
cout << ",no-interconnect";
|
||||
|
||||
if (gn_cadence_types_flag)
|
||||
cout << ",xtypes";
|
||||
else
|
||||
|
|
|
|||
|
|
@ -572,8 +572,15 @@ void NetScope::add_module_port_info( unsigned idx, perm_string name, PortType::E
|
|||
info.name = name;
|
||||
info.type = ptype;
|
||||
info.width = width;
|
||||
info.buffer = nullptr;
|
||||
}
|
||||
|
||||
PortInfo* NetScope::get_module_port_info( unsigned idx )
|
||||
{
|
||||
ivl_assert(*this, type_ == MODULE);
|
||||
ivl_assert(*this, ports_.size() > idx);
|
||||
return &ports_[idx];
|
||||
}
|
||||
|
||||
unsigned NetScope::module_port_nets() const
|
||||
{
|
||||
|
|
@ -872,3 +879,4 @@ void NetScope::add_tie_lo(Design*des)
|
|||
connect(sig->pin(0), tie_lo_->pin(0));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1966,8 +1966,8 @@ unsigned NetSignExtend::width() const
|
|||
return width_;
|
||||
}
|
||||
|
||||
NetBUFZ::NetBUFZ(NetScope*s, perm_string n, unsigned w, bool trans)
|
||||
: NetNode(s, n, 2), width_(w), transparent_(trans)
|
||||
NetBUFZ::NetBUFZ(NetScope*s, perm_string n, unsigned w, bool trans, int port_info_index)
|
||||
: NetNode(s, n, 2), width_(w), transparent_(trans), port_info_index_(port_info_index)
|
||||
{
|
||||
pin(0).set_dir(Link::OUTPUT);
|
||||
pin(1).set_dir(Link::INPUT);
|
||||
|
|
|
|||
|
|
@ -660,6 +660,7 @@ struct PortInfo
|
|||
PortType::Enum type;
|
||||
unsigned long width;
|
||||
perm_string name;
|
||||
ivl_net_logic_t buffer;
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -1127,6 +1128,8 @@ class NetScope : public Definitions, public Attrib {
|
|||
PortType::Enum type,
|
||||
unsigned long width );
|
||||
|
||||
PortInfo* get_module_port_info(unsigned idx);
|
||||
|
||||
const std::vector<PortInfo> &module_port_info() const;
|
||||
|
||||
/* Scopes have their own time units and time precision. The
|
||||
|
|
@ -2359,11 +2362,12 @@ class NetSubstitute : public NetNode {
|
|||
class NetBUFZ : public NetNode {
|
||||
|
||||
public:
|
||||
explicit NetBUFZ(NetScope*s, perm_string n, unsigned wid, bool transp);
|
||||
explicit NetBUFZ(NetScope*s, perm_string n, unsigned wid, bool transp, int port_info_index = -1);
|
||||
~NetBUFZ();
|
||||
|
||||
unsigned width() const;
|
||||
bool transparent() const { return transparent_; }
|
||||
int port_info_index() const { return port_info_index_; }
|
||||
|
||||
virtual void dump_node(std::ostream&, unsigned ind) const;
|
||||
virtual bool emit_node(struct target_t*) const;
|
||||
|
|
@ -2371,6 +2375,7 @@ class NetBUFZ : public NetNode {
|
|||
private:
|
||||
unsigned width_;
|
||||
bool transparent_;
|
||||
int port_info_index_;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
|||
11
t-dll-api.cc
11
t-dll-api.cc
|
|
@ -992,6 +992,12 @@ extern "C" unsigned ivl_logic_width(ivl_net_logic_t net)
|
|||
return net->width_;
|
||||
}
|
||||
|
||||
extern "C" unsigned ivl_logic_port_buffer(ivl_net_logic_t net)
|
||||
{
|
||||
assert(net);
|
||||
return net->is_port_buffer;
|
||||
}
|
||||
|
||||
extern "C" int ivl_udp_sequ(ivl_udp_t net)
|
||||
{
|
||||
assert(net);
|
||||
|
|
@ -2315,6 +2321,11 @@ extern "C" unsigned ivl_scope_mod_module_port_width(ivl_scope_t net, unsigned id
|
|||
return net->module_ports_info[idx].width;
|
||||
}
|
||||
|
||||
extern "C" ivl_net_logic_t ivl_scope_mod_module_port_buffer(ivl_scope_t net, unsigned idx )
|
||||
{
|
||||
assert(net);
|
||||
return (ivl_net_logic_t)net->module_ports_info[idx].buffer;
|
||||
}
|
||||
|
||||
extern "C" unsigned ivl_scope_ports(ivl_scope_t net)
|
||||
{
|
||||
|
|
|
|||
11
t-dll.cc
11
t-dll.cc
|
|
@ -856,6 +856,7 @@ bool dll_target::bufz(const NetBUFZ*net)
|
|||
obj->type_ = net->transparent()? IVL_LO_BUFT : IVL_LO_BUFZ;
|
||||
obj->width_= net->width();
|
||||
obj->is_cassign = 0;
|
||||
obj->is_port_buffer = net->port_info_index() >= 0;
|
||||
obj->npins_= 2;
|
||||
obj->pins_ = new ivl_nexus_t[2];
|
||||
FILE_NAME(obj, net);
|
||||
|
|
@ -892,6 +893,14 @@ bool dll_target::bufz(const NetBUFZ*net)
|
|||
|
||||
scope_add_logic(scop, obj);
|
||||
|
||||
// Add bufz to the corresponding port_info entry,
|
||||
// if it is an input / output buffer
|
||||
// This is needed for the SDF interconnect feature
|
||||
// to access the buffers directly from the port_info
|
||||
if (obj->is_port_buffer) {
|
||||
scop->module_ports_info[net->port_info_index()].buffer = obj;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -959,6 +968,7 @@ void dll_target::logic(const NetLogic*net)
|
|||
struct ivl_net_logic_s *obj = new struct ivl_net_logic_s;
|
||||
|
||||
obj->width_ = net->width();
|
||||
obj->is_port_buffer = 0;
|
||||
|
||||
FILE_NAME(obj, net);
|
||||
|
||||
|
|
@ -1427,6 +1437,7 @@ void dll_target::udp(const NetUDP*net)
|
|||
struct ivl_net_logic_s *obj = new struct ivl_net_logic_s;
|
||||
|
||||
obj->type_ = IVL_LO_UDP;
|
||||
obj->is_port_buffer = 0;
|
||||
FILE_NAME(obj, net);
|
||||
|
||||
/* The NetUDP class hasn't learned about width yet, so we
|
||||
|
|
|
|||
1
t-dll.h
1
t-dll.h
|
|
@ -530,6 +530,7 @@ struct ivl_net_logic_s {
|
|||
ivl_logic_t type_;
|
||||
unsigned width_;
|
||||
unsigned is_cassign;
|
||||
unsigned is_port_buffer;
|
||||
ivl_udp_t udp;
|
||||
|
||||
perm_string name_;
|
||||
|
|
|
|||
|
|
@ -308,6 +308,9 @@ int signal_is_return_value(ivl_signal_t sig)
|
|||
*/
|
||||
int can_elide_bufz(ivl_net_logic_t net, ivl_nexus_ptr_t nptr)
|
||||
{
|
||||
// If bufz is a module input/output buffer do not elide
|
||||
if (ivl_logic_port_buffer(net)) return 0;
|
||||
|
||||
ivl_nexus_t in_n, out_n;
|
||||
unsigned idx;
|
||||
|
||||
|
|
@ -2400,17 +2403,20 @@ int draw_scope(ivl_scope_t net, ivl_scope_t parent)
|
|||
|
||||
if( ivl_scope_type(net) == IVL_SCT_MODULE ) {
|
||||
|
||||
// Port data for VPI: needed for vpiPorts property of vpiModule
|
||||
for( idx = 0; idx < ivl_scope_mod_module_ports(net); ++idx ) {
|
||||
const char *name = ivl_scope_mod_module_port_name(net,idx);
|
||||
ivl_signal_port_t ptype = ivl_scope_mod_module_port_type(net,idx);
|
||||
unsigned width = ivl_scope_mod_module_port_width(net,idx);
|
||||
if( name == 0 )
|
||||
name = "";
|
||||
fprintf( vvp_out, " .port_info %u %s %u \"%s\";\n",
|
||||
idx, vvp_port_info_type_str(ptype), width,
|
||||
vvp_mangle_name(name) );
|
||||
}
|
||||
// Port data for VPI: needed for vpiPorts property of vpiModule
|
||||
for( idx = 0; idx < ivl_scope_mod_module_ports(net); ++idx ) {
|
||||
const char *name = ivl_scope_mod_module_port_name(net,idx);
|
||||
ivl_signal_port_t ptype = ivl_scope_mod_module_port_type(net,idx);
|
||||
unsigned width = ivl_scope_mod_module_port_width(net,idx);
|
||||
ivl_net_logic_t buffer = ivl_scope_mod_module_port_buffer(net,idx);
|
||||
if( name == 0 )
|
||||
name = "";
|
||||
fprintf( vvp_out, " .port_info %u %s %u \"%s\"",
|
||||
idx, vvp_port_info_type_str(ptype), width,
|
||||
vvp_mangle_name(name) );
|
||||
if (buffer) fprintf( vvp_out, " L_%p;\n", buffer);
|
||||
else fprintf( vvp_out, ";\n");
|
||||
}
|
||||
}
|
||||
|
||||
for (idx = 0 ; idx < ivl_scope_params(net) ; idx += 1) {
|
||||
|
|
@ -2529,3 +2535,4 @@ int draw_scope(ivl_scope_t net, ivl_scope_t parent)
|
|||
ivl_scope_children(net, (ivl_scope_f*) draw_scope, net);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -60,6 +60,11 @@ vpiHandle vpi_handle_by_index(vpiHandle ref, PLI_INT32 idx)
|
|||
assert(vpip_routines);
|
||||
return vpip_routines->handle_by_index(ref, idx);
|
||||
}
|
||||
vpiHandle vpi_handle_multi(PLI_INT32 type, vpiHandle ref1, vpiHandle ref2)
|
||||
{
|
||||
assert(vpip_routines);
|
||||
return vpip_routines->handle_multi(type, ref1, ref2);
|
||||
}
|
||||
|
||||
// for traversing relationships
|
||||
|
||||
|
|
|
|||
|
|
@ -42,6 +42,7 @@ char sdf_use_hchar = '.';
|
|||
struct sdf_delay_s delay;
|
||||
struct port_with_edge_s port_with_edge;
|
||||
struct sdf_delval_list_s delval_list;
|
||||
struct interconnect_port_s interconnect_port;
|
||||
};
|
||||
|
||||
%token K_ABSOLUTE K_CELL K_CELLTYPE K_COND K_CONDELSE K_DATE K_DELAYFILE
|
||||
|
|
@ -63,7 +64,9 @@ char sdf_use_hchar = '.';
|
|||
%type <string_val> celltype
|
||||
%type <string_val> cell_instance
|
||||
%type <string_val> hierarchical_identifier
|
||||
%type <string_val> port port_instance port_interconnect
|
||||
%type <string_val> port port_instance
|
||||
|
||||
%type <interconnect_port> port_interconnect
|
||||
|
||||
%type <real_val> signed_real_number
|
||||
%type <delay> delval rvalue_opt rvalue rtriple signed_real_number_opt
|
||||
|
|
@ -157,26 +160,31 @@ 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",
|
||||
|
|
@ -195,11 +203,10 @@ 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",
|
||||
|
|
@ -335,15 +342,22 @@ del_def
|
|||
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_warning) vpi_printf("SDF WARNING: %s:%d: "
|
||||
"INTERCONNECT not supported.\n",
|
||||
sdf_parse_path, @2.first_line);
|
||||
free($3);
|
||||
free($4);
|
||||
{
|
||||
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);
|
||||
}
|
||||
;
|
||||
|
||||
tchk_def_list
|
||||
|
|
@ -396,13 +410,13 @@ cond_edge_identifier
|
|||
|
||||
timing_check_condition
|
||||
: port_interconnect
|
||||
{ free($1); }
|
||||
{ free($1.name); }
|
||||
| '~' port_interconnect
|
||||
{ free($2); }
|
||||
{ free($2.name); }
|
||||
| '!' port_interconnect
|
||||
{ free($2); }
|
||||
{ free($2.name); }
|
||||
| port_interconnect equality_operator scalar_constant
|
||||
{ free($1); }
|
||||
{ free($1.name); }
|
||||
;
|
||||
|
||||
/* This is not complete! */
|
||||
|
|
@ -455,12 +469,17 @@ port
|
|||
/* | hierarchical_identifier '[' INTEGER ']' */
|
||||
;
|
||||
|
||||
/* Since INTERCONNECT is ignored we can also ignore a vector bit. */
|
||||
port_interconnect
|
||||
: hierarchical_identifier
|
||||
{ $$ = $1; }
|
||||
{
|
||||
struct interconnect_port_s tmp = {$1, false, 0};
|
||||
$$ = tmp;
|
||||
}
|
||||
| hierarchical_identifier '[' INTEGER ']'
|
||||
{ $$ = $1;}
|
||||
{
|
||||
struct interconnect_port_s tmp = {$1, true, $3};
|
||||
$$ = tmp;
|
||||
}
|
||||
;
|
||||
|
||||
port_edge
|
||||
|
|
|
|||
|
|
@ -24,11 +24,6 @@
|
|||
* used to share declarations between the parse and the lexor.
|
||||
*/
|
||||
|
||||
struct port_with_edge_s {
|
||||
int vpi_edge;
|
||||
char*string_val;
|
||||
};
|
||||
|
||||
/* Path to source for error messages. */
|
||||
extern const char*sdf_parse_path;
|
||||
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
*/
|
||||
|
||||
# include <stdio.h>
|
||||
# include <stdbool.h>
|
||||
|
||||
/*
|
||||
* Invoke the parser to parse the opened SDF file. The fd is the SDF
|
||||
|
|
@ -48,10 +49,28 @@ struct sdf_delval_list_s {
|
|||
struct sdf_delay_s val[12];
|
||||
};
|
||||
|
||||
struct port_with_edge_s {
|
||||
int vpi_edge;
|
||||
char*string_val;
|
||||
};
|
||||
|
||||
struct interconnect_port_s {
|
||||
char* name;
|
||||
bool has_index;
|
||||
int index; // invalid if has_index is false
|
||||
};
|
||||
|
||||
extern void sdf_select_instance(const char*celltype, const char*inst,
|
||||
const int sdf_lineno);
|
||||
|
||||
extern void sdf_iopath_delays(int vpi_edge, const char*src, const char*dst,
|
||||
const struct sdf_delval_list_s*delval,
|
||||
const int sdf_lineno);
|
||||
|
||||
extern void sdf_interconnect_delays(struct interconnect_port_s port1,
|
||||
struct interconnect_port_s port2,
|
||||
const struct sdf_delval_list_s*delval_list,
|
||||
const int sdf_lineno);
|
||||
|
||||
#endif /* IVL_sdf_priv_h */
|
||||
|
||||
|
|
|
|||
134
vpi/sys_sdf.c
134
vpi/sys_sdf.c
|
|
@ -76,8 +76,11 @@ void sdf_select_instance(const char*celltype, const char*cellinst, const int sdf
|
|||
|
||||
/* Test for wildcard character */
|
||||
if (cellinst == NULL) {
|
||||
sdf_warn_file_line(sdf_lineno);
|
||||
vpi_printf("Wildcard cell instance specification (*) currently not supported.\n");
|
||||
if (sdf_flag_warning) {
|
||||
vpi_printf("SDF WARNING: %s:%d: sorry: "
|
||||
"Wildcard cell instance specification (*) currently not supported.\n",
|
||||
sdf_fname, sdf_lineno);
|
||||
}
|
||||
sdf_cur_cell = 0;
|
||||
return;
|
||||
}
|
||||
|
|
@ -96,9 +99,8 @@ void sdf_select_instance(const char*celltype, const char*cellinst, const int sdf
|
|||
|
||||
vpiHandle tmp_scope = find_scope(scope, buffer);
|
||||
if (tmp_scope == 0) {
|
||||
sdf_warn_file_line(sdf_lineno);
|
||||
vpi_printf("Cannot find %s in scope %s.\n",
|
||||
buffer, vpi_get_str(vpiFullName, scope));
|
||||
vpi_printf("SDF ERROR: %s:%d: Cannot find %s in scope %s.\n",
|
||||
sdf_fname, sdf_lineno, buffer, vpi_get_str(vpiFullName, scope));
|
||||
break;
|
||||
}
|
||||
assert(tmp_scope);
|
||||
|
|
@ -113,24 +115,21 @@ void sdf_select_instance(const char*celltype, const char*cellinst, const int sdf
|
|||
else
|
||||
sdf_cur_cell = find_scope(scope, src);
|
||||
if (sdf_cur_cell == 0) {
|
||||
sdf_warn_file_line(sdf_lineno);
|
||||
vpi_printf("Unable to find %s in scope %s.\n",
|
||||
src, vpi_get_str(vpiFullName, scope));
|
||||
vpi_printf("SDF ERROR: %s:%d: Unable to find %s in scope %s.\n",
|
||||
sdf_fname, sdf_lineno, src, vpi_get_str(vpiFullName, scope));
|
||||
return;
|
||||
}
|
||||
|
||||
/* The scope that matches should be a module. */
|
||||
if (vpi_get(vpiType,sdf_cur_cell) != vpiModule) {
|
||||
sdf_warn_file_line(sdf_lineno);
|
||||
vpi_printf("Scope %s in %s is not a module.\n",
|
||||
src, vpi_get_str(vpiFullName, scope));
|
||||
vpi_printf("SDF ERROR: %s:%d: Scope %s in %s is not a module.\n",
|
||||
sdf_fname, sdf_lineno, src, vpi_get_str(vpiFullName, scope));
|
||||
}
|
||||
|
||||
/* The matching scope (a module) should have the expected type. */
|
||||
if (strcmp(celltype,vpi_get_str(vpiDefName,sdf_cur_cell)) != 0) {
|
||||
sdf_warn_file_line(sdf_lineno);
|
||||
vpi_printf("Module %s in %s is not a %s; it is a ", src,
|
||||
vpi_get_str(vpiFullName, scope), celltype);
|
||||
vpi_printf("SDF ERROR: %s:%d: Module %s in %s is not a %s; it is a ",
|
||||
sdf_fname, sdf_lineno, src, vpi_get_str(vpiFullName, scope), celltype);
|
||||
vpi_printf("%s\n", vpi_get_str(vpiDefName, sdf_cur_cell));
|
||||
}
|
||||
|
||||
|
|
@ -147,6 +146,98 @@ static const char*edge_str(int vpi_edge)
|
|||
return "edge.. ";
|
||||
}
|
||||
|
||||
vpiHandle get_port_handle(char* port_name, const int sdf_lineno)
|
||||
{
|
||||
vpiHandle scope = sdf_cur_cell;
|
||||
|
||||
// Get occurences of '.' in the name
|
||||
int submodules = 0;
|
||||
|
||||
for (int i=0; port_name[i] != '\0'; i++) {
|
||||
if (port_name[i] == '.') submodules++;
|
||||
}
|
||||
|
||||
// Extract the first token
|
||||
char* token = strtok(port_name, ".");;
|
||||
|
||||
// Change scope into submodule
|
||||
while (submodules--) {
|
||||
scope = vpi_handle_by_name(token, scope);
|
||||
|
||||
if (!scope) vpi_printf("SDF ERROR: %s:%d: Submodule %s in port path not found!\n", sdf_fname, sdf_lineno, token);
|
||||
|
||||
// Extract next token
|
||||
token = strtok(NULL, ".");
|
||||
}
|
||||
|
||||
// Iterate over ports
|
||||
vpiHandle port_i = vpi_iterate(vpiPort, scope) ;
|
||||
vpiHandle port;
|
||||
vpiHandle port_handle = NULL;
|
||||
|
||||
while ((port=vpi_scan(port_i)) != NULL) {
|
||||
char *port_name_ = vpi_get_str(vpiName, port) ;
|
||||
|
||||
if (strcmp(port_name_, token) == 0) {
|
||||
if (port_handle != NULL) {
|
||||
if (sdf_flag_warning) vpi_printf("SDF WARNING: %s:%d: Found multiple matching ports for %s !\n", sdf_fname, sdf_lineno, token);
|
||||
}
|
||||
port_handle = port;
|
||||
}
|
||||
}
|
||||
|
||||
return port_handle;
|
||||
}
|
||||
|
||||
|
||||
void sdf_interconnect_delays(struct interconnect_port_s port1, struct interconnect_port_s port2,
|
||||
const struct sdf_delval_list_s*delval_list,
|
||||
const int sdf_lineno)
|
||||
{
|
||||
|
||||
// Get handles for both ports
|
||||
// After calling get_port_handle, the name is invalid
|
||||
vpiHandle port1_handle = get_port_handle(port1.name, sdf_lineno);
|
||||
vpiHandle port2_handle = get_port_handle(port2.name, sdf_lineno);
|
||||
|
||||
if (port1_handle && port2_handle) {
|
||||
// Get interModPath for the two ports
|
||||
vpiHandle intermodpath = vpi_handle_multi(vpiInterModPath, port1_handle, port2_handle);
|
||||
|
||||
if (intermodpath) {
|
||||
if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Created a vpiInterModPath\n", sdf_fname, sdf_lineno);
|
||||
|
||||
s_vpi_delay delays;
|
||||
struct t_vpi_time delay_vals[12];
|
||||
|
||||
// Initialize delay structure
|
||||
delays.da = delay_vals;
|
||||
delays.no_of_delays = delval_list->count;
|
||||
delays.time_type = vpiScaledRealTime;
|
||||
delays.mtm_flag = 0;
|
||||
delays.append_flag = 0;
|
||||
delays.pulsere_flag = 0;
|
||||
vpi_get_delays(intermodpath, &delays);
|
||||
|
||||
for (int idx = 0 ; idx < delval_list->count ; idx += 1) {
|
||||
delay_vals[idx].type = vpiScaledRealTime;
|
||||
if (delval_list->val[idx].defined) {
|
||||
if (sdf_flag_inform) vpi_printf("SDF INFO: %s:%d: Putting delay: %f for index %d\n",
|
||||
sdf_fname, sdf_lineno, delval_list->val[idx].value, idx);
|
||||
delay_vals[idx].real = delval_list->val[idx].value;
|
||||
}
|
||||
}
|
||||
|
||||
// Put the new delays
|
||||
vpi_put_delays(intermodpath, &delays);
|
||||
} else {
|
||||
vpi_printf("SDF ERROR: %s:%d: Could not find intermodpath!\n", sdf_fname, sdf_lineno);
|
||||
}
|
||||
} else {
|
||||
vpi_printf("SDF ERROR: %s:%d: Could not find handles for both ports!\n", sdf_fname, sdf_lineno);
|
||||
}
|
||||
}
|
||||
|
||||
void sdf_iopath_delays(int vpi_edge, const char*src, const char*dst,
|
||||
const struct sdf_delval_list_s*delval_list,
|
||||
const int sdf_lineno)
|
||||
|
|
@ -214,10 +305,10 @@ void sdf_iopath_delays(int vpi_edge, const char*src, const char*dst,
|
|||
}
|
||||
|
||||
if (match_count == 0) {
|
||||
sdf_warn_file_line(sdf_lineno);
|
||||
vpi_printf("Unable to match ModPath %s%s -> %s in %s\n",
|
||||
edge_str(vpi_edge), src, dst,
|
||||
vpi_get_str(vpiFullName, sdf_cur_cell));
|
||||
vpi_printf("SDF ERROR: %s:%d: Unable to match ModPath %s%s -> %s in %s\n",
|
||||
sdf_fname, sdf_lineno,
|
||||
edge_str(vpi_edge), src, dst,
|
||||
vpi_get_str(vpiFullName, sdf_cur_cell));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -309,6 +400,13 @@ static PLI_INT32 sys_sdf_annotate_calltf(ICARUS_VPI_CONST PLI_BYTE8*name)
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (sdf_flag_inform) {
|
||||
vpi_printf("SDF INFO: Loading %s from %s:%d\n",
|
||||
fname,
|
||||
vpi_get_str(vpiFile, callh),
|
||||
(int)vpi_get(vpiLineNo, callh));
|
||||
}
|
||||
|
||||
sdf_fd = fopen(fname, "r");
|
||||
if (sdf_fd == 0) {
|
||||
vpi_printf("SDF WARNING: %s:%d: ", vpi_get_str(vpiFile, callh),
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ void vpi_get_systf_info(vpiHandle, p_vpi_systf_data) { }
|
|||
|
||||
vpiHandle vpi_handle_by_name(const char*, vpiHandle) { return 0; }
|
||||
vpiHandle vpi_handle_by_index(vpiHandle, PLI_INT32) { return 0; }
|
||||
vpiHandle vpi_handle_multi(PLI_INT32, vpiHandle, vpiHandle) { return 0; }
|
||||
|
||||
// for traversing relationships
|
||||
|
||||
|
|
@ -195,6 +196,7 @@ vpip_routines_s vpi_routines = {
|
|||
.get_systf_info = vpi_get_systf_info,
|
||||
.handle_by_name = vpi_handle_by_name,
|
||||
.handle_by_index = vpi_handle_by_index,
|
||||
.handle_multi = vpi_handle_multi,
|
||||
.handle = vpi_handle,
|
||||
.iterate = vpi_iterate,
|
||||
.scan = vpi_scan,
|
||||
|
|
|
|||
|
|
@ -277,6 +277,7 @@ typedef struct t_vpi_delay {
|
|||
#define vpiConstant 7
|
||||
#define vpiFunction 20
|
||||
#define vpiIntegerVar 25
|
||||
#define vpiInterModPath 26
|
||||
#define vpiIterator 27
|
||||
#define vpiMemory 29
|
||||
#define vpiMemoryWord 30
|
||||
|
|
@ -534,6 +535,7 @@ extern vpiHandle vpi_iterate(PLI_INT32 type, vpiHandle ref);
|
|||
extern vpiHandle vpi_scan(vpiHandle iter);
|
||||
extern vpiHandle vpi_handle_by_index(vpiHandle ref, PLI_INT32 idx);
|
||||
extern vpiHandle vpi_handle_by_name(const char*name, vpiHandle scope);
|
||||
extern vpiHandle vpi_handle_multi(PLI_INT32 type, vpiHandle ref1, vpiHandle ref2);
|
||||
|
||||
extern void vpi_get_time(vpiHandle obj, s_vpi_time*t);
|
||||
extern PLI_INT32 vpi_get(int property, vpiHandle ref);
|
||||
|
|
@ -697,6 +699,7 @@ typedef struct {
|
|||
void (*get_systf_info)(vpiHandle, p_vpi_systf_data);
|
||||
vpiHandle (*handle_by_name)(const char*, vpiHandle);
|
||||
vpiHandle (*handle_by_index)(vpiHandle, PLI_INT32);
|
||||
vpiHandle (*handle_multi)(PLI_INT32, vpiHandle, vpiHandle);
|
||||
vpiHandle (*handle)(PLI_INT32, vpiHandle);
|
||||
vpiHandle (*iterate)(PLI_INT32, vpiHandle);
|
||||
vpiHandle (*scan)(vpiHandle);
|
||||
|
|
|
|||
|
|
@ -514,7 +514,7 @@ extern void compile_var_queue(char*label, char*name, unsigned size);
|
|||
* nets connected through module ports.
|
||||
*/
|
||||
|
||||
extern void compile_port_info( unsigned index, int vpi_port_type, unsigned width, const char *name );
|
||||
extern void compile_port_info( unsigned index, int vpi_port_type, unsigned width, const char *name, char* buffer );
|
||||
|
||||
|
||||
/*
|
||||
|
|
|
|||
348
vvp/delay.cc
348
vvp/delay.cc
|
|
@ -1115,3 +1115,351 @@ struct __vpiModPathSrc* vpip_make_modpath_src(struct __vpiModPath*path,
|
|||
|
||||
return obj;
|
||||
}
|
||||
|
||||
vvp_fun_intermodpath::vvp_fun_intermodpath(vvp_net_t*net, unsigned width)
|
||||
: net_(net)
|
||||
{
|
||||
for (unsigned idx = 0 ; idx < 12 ; idx += 1)
|
||||
delay_[idx] = 0;
|
||||
|
||||
cur_vec4_ = vvp_vector4_t(width, BIT4_X);
|
||||
schedule_init_propagate(net_, cur_vec4_);
|
||||
}
|
||||
|
||||
vvp_fun_intermodpath::~vvp_fun_intermodpath()
|
||||
{
|
||||
}
|
||||
|
||||
void vvp_fun_intermodpath::get_delay12(vvp_time64_t val[12]) const
|
||||
{
|
||||
for (unsigned idx = 0 ; idx < 12 ; idx += 1)
|
||||
val[idx] = delay_[idx];
|
||||
}
|
||||
|
||||
void vvp_fun_intermodpath::put_delay12(const vvp_time64_t val[12])
|
||||
{
|
||||
for (unsigned idx = 0 ; idx < 12 ; idx += 1)
|
||||
delay_[idx] = val[idx];
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME: this implementation currently only uses the maximum delay
|
||||
* from all the bit changes in the vectors. If there are multiple
|
||||
* changes with different delays, then the results would be
|
||||
* wrong. What should happen is that if there are multiple changes,
|
||||
* multiple vectors approaching the result should be scheduled.
|
||||
*/
|
||||
void vvp_fun_intermodpath::recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
|
||||
vvp_context_t)
|
||||
{
|
||||
/* Only the first port is used. */
|
||||
if (port.port() > 0)
|
||||
return;
|
||||
|
||||
if (cur_vec4_.eeq(bit))
|
||||
return;
|
||||
|
||||
/* Given the scheduled output time, create an output event. */
|
||||
vvp_time64_t use_delay = delay_from_edge(cur_vec4_.value(0),
|
||||
bit.value(0),
|
||||
delay_);
|
||||
|
||||
/* FIXME: This bases the edge delay on only the least
|
||||
bit. This is WRONG! I need to find all the possible delays,
|
||||
and schedule an event for each partial change. Hard! */
|
||||
for (unsigned idx = 1 ; idx < bit.size() ; idx += 1) {
|
||||
vvp_time64_t tmp = delay_from_edge(cur_vec4_.value(idx),
|
||||
bit.value(idx),
|
||||
delay_);
|
||||
/* If the current and new bit values match then no delay
|
||||
* is needed for this bit. */
|
||||
if (cur_vec4_.value(idx) == bit.value(idx)) continue;
|
||||
assert(tmp == use_delay);
|
||||
}
|
||||
|
||||
cur_vec4_ = bit;
|
||||
schedule_generic(this, use_delay, false);
|
||||
}
|
||||
|
||||
void vvp_fun_intermodpath::run_run()
|
||||
{
|
||||
net_->send_vec4(cur_vec4_, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* All the below routines that begin with
|
||||
* intermodpath_* belong the internal function
|
||||
* of an vpiInterModPath object. This is used to
|
||||
* make some specific delays path operations
|
||||
*
|
||||
*/
|
||||
static int intermodpath_get(int, vpiHandle ref)
|
||||
{
|
||||
struct __vpiInterModPath*obj =dynamic_cast<__vpiInterModPath*>(ref);
|
||||
assert(obj);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void intermodpath_get_value(vpiHandle ref, p_vpi_value)
|
||||
{
|
||||
struct __vpiInterModPath* intermodpath = dynamic_cast<__vpiInterModPath*>(ref);
|
||||
assert(intermodpath);
|
||||
return;
|
||||
}
|
||||
|
||||
static vpiHandle intermodpath_put_value(vpiHandle ref, s_vpi_value *, int )
|
||||
{
|
||||
struct __vpiInterModPath* intermodpath = dynamic_cast<__vpiInterModPath*>(ref);
|
||||
assert(intermodpath);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static vpiHandle intermodpath_get_handle(int code, vpiHandle ref)
|
||||
{
|
||||
struct __vpiInterModPath*rfp = dynamic_cast<__vpiInterModPath*>(ref);
|
||||
assert(rfp);
|
||||
|
||||
switch (code) {
|
||||
|
||||
case vpiScope:
|
||||
return rfp->scope;
|
||||
|
||||
case vpiModule:
|
||||
{ __vpiScope*scope = rfp->scope;
|
||||
while (scope && scope->get_type_code() != vpiModule)
|
||||
scope = scope->scope;
|
||||
assert(scope);
|
||||
return scope;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static vpiHandle intermodpath_iterate(int code, vpiHandle ref)
|
||||
{
|
||||
struct __vpiInterModPath*rfp = dynamic_cast<__vpiInterModPath*>(ref);
|
||||
assert(rfp);
|
||||
|
||||
// For now intermodpaths only support exactly two ports
|
||||
switch (code) {
|
||||
case vpiPort: {
|
||||
vpiHandle*args = (vpiHandle*)calloc(2, sizeof(vpiHandle*));
|
||||
args[0] = rfp->port1;
|
||||
args[1] = rfp->port2;
|
||||
return vpip_make_iterator(2, args, true);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This routine will put specific dimension of delay[] values
|
||||
* into a vpiHandle. In this case, we will put
|
||||
* specific delays values in a vpiInterModPath object
|
||||
*
|
||||
*/
|
||||
static void intermodpath_put_delays (vpiHandle ref, p_vpi_delay delays)
|
||||
{
|
||||
vvp_time64_t tmp[12];
|
||||
int idx;
|
||||
struct __vpiInterModPath * src = dynamic_cast<__vpiInterModPath*>(ref) ;
|
||||
assert(src) ;
|
||||
|
||||
vvp_fun_intermodpath *fun = dynamic_cast<vvp_fun_intermodpath*>(src->net->fun);
|
||||
assert( fun );
|
||||
|
||||
typedef unsigned char map_array_t[12];
|
||||
// Only the first six entries are used for the less than twelve maps.
|
||||
static const map_array_t map_1 = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
static const map_array_t map_2 = {0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0};
|
||||
static const map_array_t map_3 = {0, 1, 2, 0, 2, 1, 0, 0, 0, 0, 0, 0};
|
||||
static const map_array_t map_6 = {0, 1, 2, 3, 4, 5, 0, 0, 0, 0, 0, 0};
|
||||
static const map_array_t map12 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
|
||||
|
||||
const map_array_t*use_map = 0;
|
||||
switch (delays->no_of_delays) {
|
||||
case 1:
|
||||
use_map = &map_1;
|
||||
break;
|
||||
case 2:
|
||||
use_map = &map_2;
|
||||
break;
|
||||
case 3:
|
||||
use_map = &map_3;
|
||||
break;
|
||||
case 6:
|
||||
use_map = &map_6;
|
||||
break;
|
||||
case 12:
|
||||
use_map = &map12;
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
if (delays->time_type == vpiSimTime) {
|
||||
for (idx = 0 ; idx < 12 ; idx += 1) {
|
||||
tmp[idx] = vpip_timestruct_to_time(delays->da+use_map[0][idx]);
|
||||
}
|
||||
} else {
|
||||
// You cannot create a modpath with a negative delay so set it
|
||||
// to zero per 1364-2005 section 14.3.1.
|
||||
for (idx = 0 ; idx < delays->no_of_delays ; idx += 1) {
|
||||
if (delays->da[idx].real < 0.0) delays->da[idx].real = 0.0;
|
||||
}
|
||||
for (idx = 0 ; idx < 12 ; idx += 1) {
|
||||
tmp[idx] = vpip_scaled_real_to_time64(delays->da[use_map[0][idx]].real,
|
||||
src->scope);
|
||||
}
|
||||
}
|
||||
|
||||
/* Now define the to-from-x delays if needed. */
|
||||
if (delays->no_of_delays <= 6) {
|
||||
/* 0->x is the minimum of 0->z and 0->1. */
|
||||
tmp[DELAY_EDGE_0x] = tmp[DELAY_EDGE_0z] < tmp[DELAY_EDGE_01] ?
|
||||
tmp[DELAY_EDGE_0z] : tmp[DELAY_EDGE_01];
|
||||
/* x->1 is the maximum of z->1 and 0->1. */
|
||||
tmp[DELAY_EDGE_x1] = tmp[DELAY_EDGE_z1] > tmp[DELAY_EDGE_01] ?
|
||||
tmp[DELAY_EDGE_z1] : tmp[DELAY_EDGE_01];
|
||||
/* 1->x is the minimum of 1->z and 1->0. */
|
||||
tmp[DELAY_EDGE_1x] = tmp[DELAY_EDGE_1z] < tmp[DELAY_EDGE_10] ?
|
||||
tmp[DELAY_EDGE_1z] : tmp[DELAY_EDGE_10];
|
||||
/* x->0 is the maximum of z->0 and 1->0. */
|
||||
tmp[DELAY_EDGE_x0] = tmp[DELAY_EDGE_z0] > tmp[DELAY_EDGE_10] ?
|
||||
tmp[DELAY_EDGE_z0] : tmp[DELAY_EDGE_10];
|
||||
/* x->z is the maximum of 1->z and 0->z. */
|
||||
tmp[DELAY_EDGE_xz] = tmp[DELAY_EDGE_1z] > tmp[DELAY_EDGE_0z] ?
|
||||
tmp[DELAY_EDGE_1z] : tmp[DELAY_EDGE_0z];
|
||||
/* z->x is the minimum of z->1 and z->0. */
|
||||
tmp[DELAY_EDGE_zx] = tmp[DELAY_EDGE_z1] < tmp[DELAY_EDGE_z0] ?
|
||||
tmp[DELAY_EDGE_z1] : tmp[DELAY_EDGE_z0];
|
||||
}
|
||||
|
||||
fun->put_delay12(tmp);
|
||||
}
|
||||
|
||||
/*
|
||||
* This routine will retrieve the delay[12] values
|
||||
* of a vpiHandle. In this case, he will get an
|
||||
* specific delays values from a vpiInterModPath
|
||||
* object
|
||||
*
|
||||
*/
|
||||
|
||||
static void intermodpath_get_delays ( vpiHandle ref, p_vpi_delay delays )
|
||||
{
|
||||
struct __vpiInterModPath*src = dynamic_cast<__vpiInterModPath*>(ref) ;
|
||||
assert(src);
|
||||
|
||||
vvp_fun_intermodpath *fun = dynamic_cast<vvp_fun_intermodpath*>(src->net->fun);
|
||||
assert(fun);
|
||||
|
||||
int idx;
|
||||
vvp_time64_t tmp[12];
|
||||
fun->get_delay12(tmp);
|
||||
|
||||
switch (delays->no_of_delays) {
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 6:
|
||||
case 12:
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
|
||||
if (delays->time_type == vpiSimTime) {
|
||||
for (idx = 0; idx < delays->no_of_delays; idx += 1) {
|
||||
vpip_time_to_timestruct(delays->da+idx, tmp[idx]);
|
||||
}
|
||||
} else {
|
||||
for (idx = 0; idx < delays->no_of_delays; idx += 1) {
|
||||
delays->da[idx].real = vpip_time_to_scaled_real(tmp[idx], src->scope);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The __vpiInterModPath class is what the VPI client sees as a
|
||||
* vpiInterModPath object.
|
||||
*/
|
||||
inline __vpiInterModPath::__vpiInterModPath()
|
||||
{ }
|
||||
|
||||
int __vpiInterModPath::get_type_code(void) const
|
||||
{ return vpiInterModPath; }
|
||||
|
||||
int __vpiInterModPath::vpi_get(int code)
|
||||
{ return intermodpath_get(code, this); }
|
||||
|
||||
void __vpiInterModPath::vpi_get_value(p_vpi_value val)
|
||||
{ intermodpath_get_value(this, val); }
|
||||
|
||||
vpiHandle __vpiInterModPath::vpi_put_value(p_vpi_value val, int flags)
|
||||
{ return intermodpath_put_value(this, val, flags); }
|
||||
|
||||
vpiHandle __vpiInterModPath::vpi_handle(int code)
|
||||
{ return intermodpath_get_handle(code, this); }
|
||||
|
||||
vpiHandle __vpiInterModPath::vpi_iterate(int code)
|
||||
{ return intermodpath_iterate(code, this); }
|
||||
|
||||
void __vpiInterModPath::vpi_get_delays(p_vpi_delay del)
|
||||
{ intermodpath_get_delays(this, del); }
|
||||
|
||||
void __vpiInterModPath::vpi_put_delays(p_vpi_delay del)
|
||||
{ intermodpath_put_delays(this, del); }
|
||||
|
||||
static int intermodpath_free_object( vpiHandle ref )
|
||||
{
|
||||
delete ref;
|
||||
return 1 ;
|
||||
}
|
||||
|
||||
__vpiHandle::free_object_fun_t __vpiInterModPath::free_object_fun(void)
|
||||
{ return &intermodpath_free_object; }
|
||||
|
||||
/*
|
||||
* This function will construct a vpiInterModPath Object.
|
||||
* give a respective "net", and will point to his
|
||||
* respective functor
|
||||
*/
|
||||
|
||||
#ifdef CHECK_WITH_VALGRIND
|
||||
static struct __vpiInterModPath**imp_list = 0;
|
||||
static unsigned imp_count = 0;
|
||||
#endif
|
||||
|
||||
struct __vpiInterModPath* vpip_make_intermodpath(vvp_net_t *net, vpiPortInfo* port1, vpiPortInfo* port2)
|
||||
{
|
||||
struct __vpiInterModPath*obj = new __vpiInterModPath;
|
||||
obj->scope = vpip_peek_current_scope ( );
|
||||
|
||||
obj->net = net;
|
||||
obj->port1 = port1;
|
||||
obj->port2 = port2;
|
||||
|
||||
#ifdef CHECK_WITH_VALGRIND
|
||||
imp_count += 1;
|
||||
imp_list = (struct __vpiInterModPath **) realloc(imp_list,
|
||||
imp_count*sizeof(struct __vpiInterModPath **));
|
||||
imp_list[imp_count-1] = obj;
|
||||
#endif
|
||||
return obj;
|
||||
}
|
||||
|
||||
#ifdef CHECK_WITH_VALGRIND
|
||||
void intermodpath_delete()
|
||||
{
|
||||
for (unsigned idx = 0; idx < mp_count; idx += 1) {
|
||||
delete imp_list[idx];
|
||||
}
|
||||
free(imp_list);
|
||||
imp_list = 0;
|
||||
imp_count = 0;
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
32
vvp/delay.h
32
vvp/delay.h
|
|
@ -234,4 +234,36 @@ class vvp_fun_modpath_edge : public vvp_fun_modpath_src {
|
|||
bool negedge_;
|
||||
};
|
||||
|
||||
/*
|
||||
* The intermodpath is used to implement the SDF INTERCONNECT feature
|
||||
* Upon a (INTERCONNECT ...) statement an intermodpath will be inserted
|
||||
* between port1 and port2 and its delay can be annotated
|
||||
*/
|
||||
class vvp_fun_intermodpath : public vvp_net_fun_t, private vvp_gen_event_s {
|
||||
|
||||
public:
|
||||
vvp_fun_intermodpath(vvp_net_t*net, unsigned width);
|
||||
~vvp_fun_intermodpath();
|
||||
|
||||
void recv_vec4(vvp_net_ptr_t port, const vvp_vector4_t&bit,
|
||||
vvp_context_t);
|
||||
|
||||
void get_delay12(vvp_time64_t out[12]) const;
|
||||
void put_delay12(const vvp_time64_t in[12]);
|
||||
|
||||
private:
|
||||
virtual void run_run();
|
||||
|
||||
private:
|
||||
vvp_net_t*net_;
|
||||
|
||||
vvp_vector4_t cur_vec4_;
|
||||
|
||||
vvp_time64_t delay_[12];
|
||||
|
||||
private: // not implemented
|
||||
vvp_fun_intermodpath(const vvp_fun_intermodpath&);
|
||||
vvp_fun_intermodpath& operator= (const vvp_fun_intermodpath&);
|
||||
};
|
||||
|
||||
#endif /* IVL_delay_H */
|
||||
|
|
|
|||
|
|
@ -713,10 +713,13 @@ statement
|
|||
|
||||
/* Port information for scopes... currently this is just meta-data for VPI queries */
|
||||
|
||||
| K_PORT_INFO T_NUMBER port_type T_NUMBER T_STRING T_SYMBOL ';'
|
||||
{ compile_port_info( $2 /* port_index */, $3, $4 /* width */,
|
||||
$5 /*&name */, $6 /* buffer */ ); }
|
||||
|
||||
| K_PORT_INFO T_NUMBER port_type T_NUMBER T_STRING ';'
|
||||
{ compile_port_info( $2 /* port_index */, $3, $4 /* width */,
|
||||
$5 /*&name */ ); }
|
||||
|
||||
$5 /*&name */, nullptr /* buffer */ ); }
|
||||
|
||||
| K_TIMESCALE T_NUMBER T_NUMBER';'
|
||||
{ compile_timescale($2, $3); }
|
||||
|
|
|
|||
139
vvp/vpi_priv.cc
139
vvp/vpi_priv.cc
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2008-2022 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2008-2023 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2023 Leo Moser (leo.moser@pm.me)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -20,6 +21,7 @@
|
|||
# include "version_base.h"
|
||||
# include "vpi_priv.h"
|
||||
# include "schedule.h"
|
||||
# include "logic.h"
|
||||
#ifdef CHECK_WITH_VALGRIND
|
||||
# include "vvp_cleanup.h"
|
||||
#endif
|
||||
|
|
@ -1553,6 +1555,140 @@ vpiHandle vpi_handle_by_name(const char *name, vpiHandle scope)
|
|||
return out;
|
||||
}
|
||||
|
||||
// Used to get intermodpath for two ports
|
||||
vpiHandle vpi_handle_multi(PLI_INT32 type,
|
||||
vpiHandle ref1,
|
||||
vpiHandle ref2)
|
||||
{
|
||||
if (vpi_trace) {
|
||||
fprintf(vpi_trace, "vpi_handle_multi(%d, %p, %p) -->\n",
|
||||
type, ref1, ref2);
|
||||
}
|
||||
|
||||
if (type != vpiInterModPath) {
|
||||
fprintf(stderr, "sorry: vpi_handle_multi currently supports"
|
||||
"only vpiInterModPath\n");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
vpiPortInfo* port1 = dynamic_cast<vpiPortInfo*>(ref1);
|
||||
|
||||
if (!port1) {
|
||||
fprintf(stderr, "sorry: second argument of vpi_handle_multi"
|
||||
"must be a vpiPort\n");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
vpiPortInfo* port2 = dynamic_cast<vpiPortInfo*>(ref2);
|
||||
|
||||
if (!port2) {
|
||||
fprintf(stderr, "sorry: third argument of vpi_handle_multi"
|
||||
"must be a vpiPort\n");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// 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
|
||||
__vpiSignal* output_signal = nullptr;
|
||||
|
||||
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) ;
|
||||
vpiHandle net;
|
||||
|
||||
while ((net = vpi_scan(net_i)) != NULL) {
|
||||
std::string net_name(vpi_get_str(vpiName, net));
|
||||
|
||||
// Compare whether the net matches with the port name
|
||||
if (net_name == port2_name) {
|
||||
output_signal = dynamic_cast<__vpiSignal*>(net);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vvp_net_t* net1 = port1->get_port();
|
||||
vvp_net_t* net2 = port2->get_port();
|
||||
|
||||
if (net1 == nullptr || net2 == nullptr) {
|
||||
fprintf(stderr, "Error: Could not find net. "
|
||||
"Did you run iverilog with '-ginterconnect'?\n");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (net1 == net2) {
|
||||
fprintf(stderr, "Error: Net for both ports is the same. "
|
||||
"Did you pass the same port twice?\n");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!dynamic_cast<vvp_fun_buft*>(net1->fun)) {
|
||||
fprintf(stderr, "Error: functor of net1 must be"
|
||||
"vvp_fun_buft\n");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!dynamic_cast<vvp_fun_buft*>(net2->fun)) {
|
||||
fprintf(stderr, "Error: functor of net2 must be"
|
||||
"vvp_fun_buft\n");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// 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) {
|
||||
vvp_net_t*new_net = new vvp_net_t;
|
||||
|
||||
// Create new node with intermodpath and connect port2 to it
|
||||
int width = 1; // TODO
|
||||
vvp_fun_intermodpath*obj = new vvp_fun_intermodpath(new_net, width);
|
||||
new_net->fun = obj;
|
||||
new_net->out_ = cur;
|
||||
|
||||
// Port2 is in the middle of the list
|
||||
// Insert intermodpath before port2 and keep everything else intact
|
||||
if (prev.ptr()) {
|
||||
prev.ptr()->port[prev.port()] = vvp_net_ptr_t(new_net, 0); // Point to port 0 of vvp_fun_intermodpath
|
||||
new_net->port[0] = cur.ptr()->port[cur.port()]; // Connect the next net in list
|
||||
cur.ptr()->port[cur.port()] = vvp_net_ptr_t(nullptr, 0); // Only port2 is connected to intermodpath
|
||||
// Port2 is first in list
|
||||
// Insert intermodpath before port2 and keep everything else intact
|
||||
} else {
|
||||
net1->out_ = vvp_net_ptr_t(new_net, 0); // Point to port 0 of vvp_fun_intermodpath
|
||||
new_net->port[0] = cur.ptr()->port[cur.port()]; // Connect the next net in list
|
||||
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) {
|
||||
net2->fil = net1->fil;
|
||||
net1->fil = nullptr;
|
||||
output_signal->node = net2;
|
||||
}
|
||||
|
||||
// Create the VPI intermodpath object
|
||||
__vpiInterModPath* intermodpath = vpip_make_intermodpath(new_net, port1, port2);
|
||||
intermodpath->intermodpath = obj;
|
||||
|
||||
// Finally done, return the intermodpath object
|
||||
return intermodpath;
|
||||
}
|
||||
|
||||
prev = cur;
|
||||
cur = cur.ptr()->port[cur.port()]; // Next net in linked list
|
||||
}
|
||||
|
||||
fprintf(stderr, "VPI error: Could not insert intermodpath!\n");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/*
|
||||
We increment the two vpi methods to enable the
|
||||
|
|
@ -1749,6 +1885,7 @@ vpip_routines_s vpi_routines = {
|
|||
.get_systf_info = vpi_get_systf_info,
|
||||
.handle_by_name = vpi_handle_by_name,
|
||||
.handle_by_index = vpi_handle_by_index,
|
||||
.handle_multi = vpi_handle_multi,
|
||||
.handle = vpi_handle,
|
||||
.iterate = vpi_iterate,
|
||||
.scan = vpi_scan,
|
||||
|
|
|
|||
|
|
@ -432,6 +432,34 @@ struct __vpiBit {
|
|||
int get_index(void) const;
|
||||
};
|
||||
|
||||
|
||||
class vpiPortInfo : public __vpiHandle {
|
||||
public:
|
||||
vpiPortInfo( __vpiScope *parent,
|
||||
unsigned index,
|
||||
int vpi_direction,
|
||||
unsigned width,
|
||||
const char *name,
|
||||
char* buffer );
|
||||
~vpiPortInfo();
|
||||
|
||||
int get_type_code(void) const { return vpiPort; }
|
||||
int get_direction(void) { return direction_; }
|
||||
|
||||
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_; }
|
||||
|
||||
private:
|
||||
__vpiScope *parent_;
|
||||
unsigned index_;
|
||||
int direction_;
|
||||
unsigned width_;
|
||||
const char *name_;
|
||||
vvp_net_t *ref_;
|
||||
};
|
||||
|
||||
/*
|
||||
* This is used by system calls to represent a bit/part select of
|
||||
* a simple variable or constant array word.
|
||||
|
|
@ -520,6 +548,43 @@ extern struct __vpiModPathSrc* vpip_make_modpath_src(struct __vpiModPath*path,
|
|||
|
||||
extern struct __vpiModPath* vpip_make_modpath(vvp_net_t *net) ;
|
||||
|
||||
/*
|
||||
*
|
||||
* The vpiInterModPath vpiHandle will define
|
||||
* a vpiInterModPath of record .intermodpath as defined
|
||||
* in the IEEE 1364
|
||||
*
|
||||
*/
|
||||
|
||||
struct __vpiInterModPath : public __vpiHandle {
|
||||
__vpiInterModPath();
|
||||
int get_type_code(void) const;
|
||||
int vpi_get(int code);
|
||||
void vpi_get_value(p_vpi_value val);
|
||||
vpiHandle vpi_put_value(p_vpi_value val, int flags);
|
||||
vpiHandle vpi_handle(int code);
|
||||
vpiHandle vpi_iterate(int code);
|
||||
void vpi_get_delays(p_vpi_delay del);
|
||||
void vpi_put_delays(p_vpi_delay del);
|
||||
free_object_fun_t free_object_fun(void);
|
||||
|
||||
__vpiScope *scope ;
|
||||
|
||||
class vvp_fun_intermodpath*intermodpath;
|
||||
|
||||
vvp_net_t *net;
|
||||
|
||||
vpiPortInfo* port1;
|
||||
vpiPortInfo* port2;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* The Function is used to create the vpiHandle
|
||||
* for vpiInterModPath
|
||||
*/
|
||||
|
||||
extern struct __vpiInterModPath* vpip_make_intermodpath(vvp_net_t *net, vpiPortInfo* port1, vpiPortInfo* port2);
|
||||
|
||||
/*
|
||||
* These methods support the vpi creation of events. The name string
|
||||
|
|
|
|||
|
|
@ -82,6 +82,9 @@ static void delete_sub_scopes(__vpiScope *scope)
|
|||
/* The destination ModPath is cleaned up later. */
|
||||
delete item;
|
||||
break;
|
||||
case vpiInterModPath:
|
||||
delete item;
|
||||
break;
|
||||
case vpiNamedEvent:
|
||||
named_event_delete(item);
|
||||
break;
|
||||
|
|
@ -659,40 +662,20 @@ unsigned vpip_add_item_to_context(automatic_hooks_s*item,
|
|||
}
|
||||
|
||||
|
||||
class vpiPortInfo : public __vpiHandle {
|
||||
public:
|
||||
vpiPortInfo( __vpiScope *parent,
|
||||
unsigned index,
|
||||
int vpi_direction,
|
||||
unsigned width,
|
||||
const char *name );
|
||||
~vpiPortInfo();
|
||||
|
||||
int get_type_code(void) const { return vpiPort; }
|
||||
|
||||
int vpi_get(int code);
|
||||
char* vpi_get_str(int code);
|
||||
vpiHandle vpi_handle(int code);
|
||||
|
||||
private:
|
||||
__vpiScope *parent_;
|
||||
unsigned index_;
|
||||
int direction_;
|
||||
unsigned width_;
|
||||
const char *name_;
|
||||
};
|
||||
|
||||
vpiPortInfo::vpiPortInfo( __vpiScope *parent,
|
||||
unsigned index,
|
||||
int vpi_direction,
|
||||
unsigned width,
|
||||
const char *name ) :
|
||||
const char *name,
|
||||
char* buffer) :
|
||||
parent_(parent),
|
||||
index_(index),
|
||||
direction_(vpi_direction),
|
||||
width_(width),
|
||||
name_(name)
|
||||
{
|
||||
if (buffer != nullptr) functor_ref_lookup(&ref_, buffer);
|
||||
else ref_ = nullptr;
|
||||
}
|
||||
|
||||
vpiPortInfo::~vpiPortInfo()
|
||||
|
|
@ -757,9 +740,9 @@ vpiHandle vpiPortInfo::vpi_handle(int code)
|
|||
* code-generators etc. There are no actual nets corresponding to instances of module ports
|
||||
* as elaboration directly connects nets connected through module ports.
|
||||
*/
|
||||
void compile_port_info( unsigned index, int vpi_direction, unsigned width, const char *name )
|
||||
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 );
|
||||
vpip_attach_to_current_scope(obj);
|
||||
vpiHandle obj = new vpiPortInfo( vpip_peek_current_scope(),
|
||||
index, vpi_direction, width, name, buffer );
|
||||
vpip_attach_to_current_scope(obj);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ vpi_get_vlog_info
|
|||
vpi_handle
|
||||
vpi_handle_by_index
|
||||
vpi_handle_by_name
|
||||
vpi_handle_multi
|
||||
vpi_iterate
|
||||
vpi_mcd_close
|
||||
vpi_mcd_flush
|
||||
|
|
|
|||
|
|
@ -1159,7 +1159,8 @@ class vvp_net_t {
|
|||
public: // Method to support $countdrivers
|
||||
void count_drivers(unsigned idx, unsigned counts[4]);
|
||||
|
||||
private:
|
||||
// This needs to be public so that SDF interconnects can be inserted
|
||||
public:
|
||||
vvp_net_ptr_t out_;
|
||||
|
||||
public: // Need a better new for these objects.
|
||||
|
|
|
|||
Loading…
Reference in New Issue