Improve SDF interconnect support, add -ginterconnect flag
This commit is contained in:
parent
adb40e7572
commit
6d3e2bf344
|
|
@ -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);
|
||||
|
|
|
|||
51
elaborate.cc
51
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,21 +1598,25 @@ 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);
|
||||
tmp->set_line(*this);
|
||||
des->add_node(tmp);
|
||||
connect(tmp->pin(1), sig->pin(0));
|
||||
// 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];
|
||||
|
||||
netvector_t*tmp2_vec = new netvector_t(sig->data_type(),
|
||||
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*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));
|
||||
sig = tmp2;
|
||||
tmp2->local_flag(true);
|
||||
tmp2->set_line(*this);
|
||||
connect(tmp->pin(0), tmp2->pin(0));
|
||||
sig = tmp2;
|
||||
}
|
||||
|
||||
// If we have a real signal driving a bit/vector port
|
||||
|
|
@ -1933,10 +1937,13 @@ 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));
|
||||
connect(prts[0]->pin(0), sig->pin(0));
|
||||
}
|
||||
|
||||
} else if (sig->vector_width()==prts_vector_width/instance.size()
|
||||
|
|
@ -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 */
|
||||
|
||||
|
|
|
|||
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)
|
||||
{
|
||||
|
|
|
|||
12
t-dll.cc
12
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,15 @@ 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 +969,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 +1438,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;
|
||||
|
||||
|
|
@ -2405,11 +2408,14 @@ int draw_scope(ivl_scope_t net, ivl_scope_t parent)
|
|||
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\";\n",
|
||||
fprintf( vvp_out, " .port_info %u %s %u \"%s\"",
|
||||
idx, vvp_port_info_type_str(ptype), width,
|
||||
vvp_mangle_name(name) );
|
||||
vvp_mangle_name(name) );
|
||||
if (buffer) fprintf( vvp_out, " L_%p;\n", buffer);
|
||||
else fprintf( vvp_out, ";\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -46,7 +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 type, vpiHandle ref1, vpiHandle ref2) { return 0; }
|
||||
vpiHandle vpi_handle_multi(PLI_INT32, vpiHandle, vpiHandle) { return 0; }
|
||||
|
||||
// for traversing relationships
|
||||
|
||||
|
|
|
|||
|
|
@ -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 );
|
||||
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -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); }
|
||||
|
|
|
|||
257
vvp/vpi_priv.cc
257
vvp/vpi_priv.cc
|
|
@ -1583,9 +1583,15 @@ void print_net_type(vvp_net_t* net1)
|
|||
else if (dynamic_cast<vvp_named_event*>(net1->fun)) std::cout << "vvp_named_event*!" << std::endl;
|
||||
else if (dynamic_cast<vvp_fun_bufif*>(net1->fun)) std::cout << "vvp_fun_bufif*!" << std::endl;
|
||||
else if (dynamic_cast<vvp_dff*>(net1->fun)) std::cout << "vvp_dff*!" << std::endl;
|
||||
else if (dynamic_cast<vvp_fun_and*>(net1->fun)) std::cout << "vvp_fun_and*!" << std::endl;
|
||||
else if (dynamic_cast<vvp_fun_equiv*>(net1->fun)) std::cout << "vvp_fun_equiv*!" << std::endl;
|
||||
else if (dynamic_cast<vvp_fun_impl*>(net1->fun)) std::cout << "vvp_fun_impl*!" << std::endl;
|
||||
else if (dynamic_cast<vvp_fun_or*>(net1->fun)) std::cout << "vvp_fun_or*!" << std::endl;
|
||||
else if (dynamic_cast<vvp_fun_xor*>(net1->fun)) std::cout << "vvp_fun_xor*!" << std::endl;
|
||||
else if (dynamic_cast<vvp_fun_boolean_*>(net1->fun)) std::cout << "vvp_fun_boolean_*!" << std::endl;
|
||||
else if (dynamic_cast<vvp_fun_buf*>(net1->fun)) std::cout << "vvp_fun_buf*!" << std::endl;
|
||||
else if (dynamic_cast<vvp_fun_buft*>(net1->fun)) std::cout << "vvp_fun_buft*!" << std::endl;
|
||||
else if (dynamic_cast<vvp_fun_bufz*>(net1->fun)) std::cout << "vvp_fun_bufz*!" << std::endl;
|
||||
else if (dynamic_cast<vvp_fun_buf*>(net1->fun)) std::cout << "vvp_fun_buf*!" << std::endl;
|
||||
else if (dynamic_cast<vvp_fun_muxz*>(net1->fun)) std::cout << "vvp_fun_muxz*!" << std::endl;
|
||||
else if (dynamic_cast<vvp_fun_muxr*>(net1->fun)) std::cout << "vvp_fun_muxr*!" << std::endl;
|
||||
else if (dynamic_cast<vvp_fun_not*>(net1->fun)) std::cout << "vvp_fun_not*!" << std::endl;
|
||||
|
|
@ -1686,70 +1692,35 @@ vpiHandle vpi_handle_multi(PLI_INT32 type,
|
|||
return nullptr;
|
||||
}*/
|
||||
|
||||
std::string port_name1(vpi_get_str(vpiName, ref1));
|
||||
std::string port_name2(vpi_get_str(vpiName, ref2));
|
||||
vvp_net_t* net1 = port1->get_port();
|
||||
vvp_net_t* net2 = port2->get_port();
|
||||
|
||||
fprintf(stderr, "port_name1: %s\n", port_name1.c_str());
|
||||
fprintf(stderr, "port_name2: %s\n", port_name2.c_str());
|
||||
|
||||
vpiHandle mod1 = vpi_handle(vpiModule, ref1);
|
||||
vpiHandle mod2 = vpi_handle(vpiModule, ref2);
|
||||
|
||||
if (!mod1) fprintf(stderr, "Cannot access module of port1!\n");
|
||||
if (!mod2) fprintf(stderr, "Cannot access module of port2!\n");
|
||||
|
||||
// Find net for port1
|
||||
vpiHandle net_i = vpi_iterate(vpiNet, mod1);
|
||||
vpiHandle net;
|
||||
vpiHandle net_handle1 = nullptr;
|
||||
|
||||
while ((net=vpi_scan(net_i)) != nullptr)
|
||||
if (net1 == nullptr || net2 == nullptr)
|
||||
{
|
||||
char *net_name = vpi_get_str(vpiName, net);
|
||||
|
||||
fprintf(stderr, "Comparing %s and %s\n", net_name, port_name1.c_str());
|
||||
if (port_name1 == net_name)
|
||||
{
|
||||
if (net_handle1 != nullptr)
|
||||
{
|
||||
fprintf(stderr, "Found multiple matching nets for %s !\n", port_name1.c_str());
|
||||
}
|
||||
fprintf(stderr, "Found handle for net %s!\n", net_name);
|
||||
net_handle1 = net;
|
||||
}
|
||||
fprintf(stderr, "Error: Could not find net. "
|
||||
"Did you run iverilog with '-ginterconnect'?\n");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Find net for port2
|
||||
net_i = vpi_iterate(vpiNet, mod2);
|
||||
vpiHandle net_handle2 = nullptr;
|
||||
|
||||
while ((net=vpi_scan(net_i)) != nullptr)
|
||||
if (!dynamic_cast<vvp_fun_buft*>(net1->fun))
|
||||
{
|
||||
char *net_name = vpi_get_str(vpiName, net);
|
||||
|
||||
fprintf(stderr, "Comparing %s and %s\n", net_name, port_name2.c_str());
|
||||
if (port_name2 == net_name)
|
||||
{
|
||||
if (net_handle2 != nullptr)
|
||||
{
|
||||
fprintf(stderr, "Found multiple matching nets for %s !\n", port_name2.c_str());
|
||||
}
|
||||
fprintf(stderr, "Found handle for net %s!\n", net_name);
|
||||
net_handle2 = net;
|
||||
}
|
||||
fprintf(stderr, "Error: functor of net1 must be"
|
||||
"vvp_fun_buft\n");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Try to access net/node behind it
|
||||
struct __vpiSignal*node1 = dynamic_cast<__vpiSignal*>(net_handle1);
|
||||
assert(node1);
|
||||
struct __vpiSignal*node2 = dynamic_cast<__vpiSignal*>(net_handle2);
|
||||
assert(node2);
|
||||
if (!dynamic_cast<vvp_fun_buft*>(net2->fun))
|
||||
{
|
||||
fprintf(stderr, "Error: functor of net2 must be"
|
||||
"vvp_fun_buft\n");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
vvp_net_t* net1 = node1->node;
|
||||
vvp_net_t* net2 = node2->node;
|
||||
std::cout << "net1: "; print_net_type(net1);
|
||||
print_port_connections(&net1->out_);
|
||||
|
||||
print_net_type(net1);
|
||||
print_net_type(net2);
|
||||
std::cout << "net2: "; print_net_type(net2);
|
||||
print_port_connections(&net2->out_);
|
||||
|
||||
// Debug information
|
||||
|
||||
|
|
@ -1767,50 +1738,35 @@ vpiHandle vpi_handle_multi(PLI_INT32 type,
|
|||
//fprintf(stderr, "net1->out_.ptr() : %p\n", net1->out_.ptr()); // vvp_net_t
|
||||
//fprintf(stderr, "net1->out_.port() : %d\n", net1->out_.port()); // input 3-0
|
||||
|
||||
// TODO don't just compare the nets, may be a problem for high fan-out nets
|
||||
if (net1 == net2)
|
||||
// TODO don't just compare the nets, may be a problem for high fan-out nets
|
||||
if (net1 == net2 )//&& port2->get_direction() == vpiOutput)
|
||||
{
|
||||
fprintf(stderr, "Same net!\n");
|
||||
return nullptr; // TODO
|
||||
|
||||
vvp_net_ptr_t* next_ptr = &net1->out_;
|
||||
// TODO Problem: this only delays the output as viewed from outside
|
||||
// because the net for output points to before inserted intermodpath
|
||||
fprintf(stderr, "Output port!\n");
|
||||
|
||||
fprintf(stderr, "Port connections:\n");
|
||||
// Check if there is already an intermodpath TODO
|
||||
|
||||
print_port_connections(next_ptr);
|
||||
fprintf(stderr, "Inserting intermodpath...\n");
|
||||
|
||||
fprintf(stderr, "End port connections:\n");
|
||||
|
||||
std::cout << *next_ptr << std::endl;
|
||||
|
||||
vvp_net_t* next_net = next_ptr->ptr();
|
||||
//assert(next_net);
|
||||
|
||||
if (!next_net) return 0;
|
||||
|
||||
print_net_type(next_net);
|
||||
|
||||
for (int i=0; i<4; i++)
|
||||
{
|
||||
fprintf(stderr, "next_net->port[%d].ptr() : %p\n", i, next_net->port[i].ptr());
|
||||
fprintf(stderr, "next_net->port[%d].port() : %d\n", i, next_net->port[i].port());
|
||||
|
||||
if (next_net->port[i].ptr()) print_net_type(next_net->port[i].ptr());
|
||||
}
|
||||
|
||||
|
||||
// May be connected to both vvp_fun_modpath_src* and vvp_fun_bufz*!
|
||||
//if (next_net->port[next_ptr->port()].ptr() == nullptr)
|
||||
//{
|
||||
//fprintf(stderr, "next_net is the only thing connected to net1/net2!\n");
|
||||
int width = 1; // TODO
|
||||
int width = 1; // TODO get width of port, check port widths are equal
|
||||
|
||||
vvp_net_t*new_net = new vvp_net_t;
|
||||
vvp_fun_intermodpath*obj = new vvp_fun_intermodpath(new_net, width);
|
||||
new_net->fun = obj;
|
||||
|
||||
new_net->out_= vvp_net_ptr_t(next_net,0); // point to port0 of net2
|
||||
// point to where net1/net2 was pointing
|
||||
vvp_net_ptr_t net1_ptr = net1->out_;
|
||||
|
||||
// net1/net2 points to intermodpath
|
||||
net1->out_ = vvp_net_ptr_t(new_net,0);
|
||||
|
||||
// out of new_net should point to net2
|
||||
new_net->out_= net1_ptr; // point to port0 of net2
|
||||
|
||||
net1->out_ = vvp_net_ptr_t(new_net,0); // point to port0 of new_net
|
||||
|
||||
__vpiInterModPath*intermodpath = vpip_make_intermodpath(new_net, port1, port2);
|
||||
intermodpath->intermodpath = obj;
|
||||
|
|
@ -1818,41 +1774,114 @@ vpiHandle vpi_handle_multi(PLI_INT32 type,
|
|||
fprintf(stderr, "Inserted vvp_fun_intermodpath!\n");
|
||||
|
||||
return intermodpath;
|
||||
//}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Different net!\n");
|
||||
|
||||
//vvp_fun_port* fun_port1 = dynamic_cast<vvp_fun_port*>(net1->fun);
|
||||
//vvp_fun_port* fun_port2 = dynamic_cast<vvp_fun_port*>(net2->fun);
|
||||
|
||||
//if (!fun_port1 || !fun_port2) fprintf(stderr, "Not vvp_fun_port!\n");
|
||||
|
||||
vvp_net_ptr_t* net1_ptr = &net1->out_;
|
||||
vvp_net_ptr_t* net2_ptr = &net2->out_;
|
||||
|
||||
// TODO follow whole linked list
|
||||
if (net1_ptr->ptr() == net2)
|
||||
fprintf(stderr, "Connected to port1:\n");
|
||||
print_port_connections(net1_ptr);
|
||||
|
||||
fprintf(stderr, "Connected to port2:\n");
|
||||
print_port_connections(net2_ptr);
|
||||
|
||||
// TODO first iterate over list and if functor is vvp_fun_intermodpath
|
||||
// then check if output is connected to net, if so return
|
||||
vvp_net_ptr_t* net_ptr = net1_ptr;
|
||||
|
||||
while (net_ptr)
|
||||
{
|
||||
vvp_net_t* next_net = net_ptr->ptr();
|
||||
|
||||
if (!next_net) break; // End of list
|
||||
|
||||
// Found a vvp_fun_intermodpath, check if port2 is connected
|
||||
if (dynamic_cast<vvp_fun_intermodpath*>(next_net->fun))
|
||||
{
|
||||
if (next_net->out_.ptr() == net2)
|
||||
{
|
||||
fprintf(stderr, "Found already existing modpath!\n");
|
||||
|
||||
// Return the intermodpath TODO is it correct to create a new object?
|
||||
// or add reference to __vpiInterModPath from vvp_fun_intermodpath
|
||||
__vpiInterModPath*intermodpath = vpip_make_intermodpath(next_net, port1, port2);
|
||||
|
||||
return intermodpath;
|
||||
}
|
||||
}
|
||||
|
||||
net_ptr = &next_net->port[net_ptr->port()];
|
||||
}
|
||||
|
||||
// Iterate over linked list until port2 is found
|
||||
net_ptr = net1_ptr;
|
||||
vvp_net_ptr_t previous_net_ptr = vvp_net_ptr_t(nullptr, 0);
|
||||
vvp_net_t* previous_net = net1;
|
||||
|
||||
while (net_ptr)
|
||||
{
|
||||
vvp_net_t* next_net = net_ptr->ptr();
|
||||
|
||||
if (!next_net) break; // End of list
|
||||
if (next_net == net2) break; // Found net2
|
||||
|
||||
previous_net_ptr = *net_ptr;
|
||||
net_ptr = &next_net->port[net_ptr->port()];
|
||||
}
|
||||
|
||||
if (!net_ptr->ptr()) return 0;
|
||||
|
||||
fprintf(stderr, "Net2 connected to net1!\n");
|
||||
|
||||
fprintf(stderr, "%p\n", previous_net);
|
||||
|
||||
fprintf(stderr, "Inserting intermodpath...\n");
|
||||
|
||||
int width = 1; // TODO get width of port, check port widths are equal
|
||||
|
||||
vvp_net_t*new_net = new vvp_net_t;
|
||||
vvp_fun_intermodpath*obj = new vvp_fun_intermodpath(new_net, width);
|
||||
new_net->fun = obj;
|
||||
|
||||
// point to where net2 was pointing
|
||||
new_net->port[0] = net_ptr->ptr()->port[net_ptr->port()];
|
||||
|
||||
// Directly connected to port1
|
||||
if (!previous_net_ptr.ptr())
|
||||
{
|
||||
fprintf(stderr, "But net1 connected to net2!\n");
|
||||
|
||||
if (net2->port[net1_ptr->port()].ptr() == nullptr)
|
||||
{
|
||||
fprintf(stderr, "Net2 is the only thing connected to net1!\n");
|
||||
|
||||
int width = 1; // TODO
|
||||
|
||||
vvp_net_t*new_net = new vvp_net_t;
|
||||
vvp_fun_intermodpath*obj = new vvp_fun_intermodpath(new_net, width);
|
||||
new_net->fun = obj;
|
||||
|
||||
new_net->out_= vvp_net_ptr_t(net2,0); // point to port0 of net2
|
||||
net1->out_ = vvp_net_ptr_t(new_net,0); // point to port0 of new_net
|
||||
|
||||
__vpiInterModPath*intermodpath = vpip_make_intermodpath(new_net, port1, port2);
|
||||
intermodpath->intermodpath = obj;
|
||||
|
||||
fprintf(stderr, "Inserted vvp_fun_intermodpath!\n");
|
||||
|
||||
return intermodpath;
|
||||
}
|
||||
net1->out_ = vvp_net_ptr_t(new_net,0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// what pointed to net2 should point to new_net
|
||||
previous_net_ptr.ptr()->port[previous_net_ptr.port()] = vvp_net_ptr_t(new_net,0);
|
||||
}
|
||||
|
||||
// out of new_net should point to net2
|
||||
new_net->out_= vvp_net_ptr_t(net2,0); // point to port0 of net2
|
||||
|
||||
|
||||
__vpiInterModPath*intermodpath = vpip_make_intermodpath(new_net, port1, port2);
|
||||
intermodpath->intermodpath = obj;
|
||||
|
||||
fprintf(stderr, "Inserted vvp_fun_intermodpath!\n");
|
||||
|
||||
fprintf(stderr, "Connected to port1:\n");
|
||||
print_port_connections(net1_ptr);
|
||||
|
||||
fprintf(stderr, "Connected to port2:\n");
|
||||
print_port_connections(net2_ptr);
|
||||
|
||||
return intermodpath;
|
||||
|
||||
}
|
||||
std::cout << "sorry: Could not insert intermodpath!" << std::endl;
|
||||
return nullptr;
|
||||
|
|
|
|||
|
|
@ -439,7 +439,8 @@ class vpiPortInfo : public __vpiHandle {
|
|||
unsigned index,
|
||||
int vpi_direction,
|
||||
unsigned width,
|
||||
const char *name );
|
||||
const char *name,
|
||||
char* buffer );
|
||||
~vpiPortInfo();
|
||||
|
||||
int get_type_code(void) const { return vpiPort; }
|
||||
|
|
@ -448,6 +449,7 @@ class vpiPortInfo : public __vpiHandle {
|
|||
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_;
|
||||
|
|
@ -455,6 +457,7 @@ class vpiPortInfo : public __vpiHandle {
|
|||
int direction_;
|
||||
unsigned width_;
|
||||
const char *name_;
|
||||
vvp_net_t *ref_;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -666,13 +666,16 @@ 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()
|
||||
|
|
@ -737,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 );
|
||||
index, vpi_direction, width, name, buffer );
|
||||
vpip_attach_to_current_scope(obj);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue