mirror of https://github.com/YosysHQ/yosys.git
Fix "verific -extnets" for more complex situations
Signed-off-by: Clifford Wolf <clifford@clifford.at>
This commit is contained in:
parent
ddc1a4488e
commit
c863796e9f
|
@ -1619,30 +1619,35 @@ struct VerificExtNets
|
||||||
int portname_cnt = 0;
|
int portname_cnt = 0;
|
||||||
|
|
||||||
// a map from Net to the same Net one level up in the design hierarchy
|
// a map from Net to the same Net one level up in the design hierarchy
|
||||||
std::map<Net*, Net*> net_level_up;
|
std::map<Net*, Net*> net_level_up_drive_up;
|
||||||
|
std::map<Net*, Net*> net_level_up_drive_down;
|
||||||
|
|
||||||
Net *get_net_level_up(Net *net)
|
Net *route_up(Net *net, bool drive_up, Net *final_net = nullptr)
|
||||||
{
|
{
|
||||||
|
auto &net_level_up = drive_up ? net_level_up_drive_up : net_level_up_drive_down;
|
||||||
|
|
||||||
if (net_level_up.count(net) == 0)
|
if (net_level_up.count(net) == 0)
|
||||||
{
|
{
|
||||||
Netlist *nl = net->Owner();
|
Netlist *nl = net->Owner();
|
||||||
|
|
||||||
// Simply return if Netlist is not unique
|
// Simply return if Netlist is not unique
|
||||||
if (nl->NumOfRefs() != 1)
|
log_assert(nl->NumOfRefs() == 1);
|
||||||
return net;
|
|
||||||
|
|
||||||
Instance *up_inst = (Instance*)nl->GetReferences()->GetLast();
|
Instance *up_inst = (Instance*)nl->GetReferences()->GetLast();
|
||||||
Netlist *up_nl = up_inst->Owner();
|
Netlist *up_nl = up_inst->Owner();
|
||||||
|
|
||||||
// create new Port
|
// create new Port
|
||||||
string name = stringf("___extnets_%d", portname_cnt++);
|
string name = stringf("___extnets_%d", portname_cnt++);
|
||||||
Port *new_port = new Port(name.c_str(), DIR_OUT);
|
Port *new_port = new Port(name.c_str(), drive_up ? DIR_OUT : DIR_IN);
|
||||||
nl->Add(new_port);
|
nl->Add(new_port);
|
||||||
net->Connect(new_port);
|
net->Connect(new_port);
|
||||||
|
|
||||||
// create new Net in up Netlist
|
// create new Net in up Netlist
|
||||||
Net *new_net = new Net(name.c_str());
|
Net *new_net = final_net;
|
||||||
up_nl->Add(new_net);
|
if (new_net == nullptr || new_net->Owner() != up_nl) {
|
||||||
|
new_net = new Net(name.c_str());
|
||||||
|
up_nl->Add(new_net);
|
||||||
|
}
|
||||||
up_inst->Connect(new_port, new_net);
|
up_inst->Connect(new_port, new_net);
|
||||||
|
|
||||||
net_level_up[net] = new_net;
|
net_level_up[net] = new_net;
|
||||||
|
@ -1651,6 +1656,39 @@ struct VerificExtNets
|
||||||
return net_level_up.at(net);
|
return net_level_up.at(net);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Net *route_up(Net *net, bool drive_up, Netlist *dest, Net *final_net = nullptr)
|
||||||
|
{
|
||||||
|
while (net->Owner() != dest)
|
||||||
|
net = route_up(net, drive_up, final_net);
|
||||||
|
if (final_net != nullptr)
|
||||||
|
log_assert(net == final_net);
|
||||||
|
return net;
|
||||||
|
}
|
||||||
|
|
||||||
|
Netlist *find_common_ancestor(Netlist *A, Netlist *B)
|
||||||
|
{
|
||||||
|
std::set<Netlist*> ancestors_of_A;
|
||||||
|
|
||||||
|
Netlist *cursor = A;
|
||||||
|
while (1) {
|
||||||
|
ancestors_of_A.insert(cursor);
|
||||||
|
if (cursor->NumOfRefs() != 1)
|
||||||
|
break;
|
||||||
|
cursor = ((Instance*)cursor->GetReferences()->GetLast())->Owner();
|
||||||
|
}
|
||||||
|
|
||||||
|
cursor = B;
|
||||||
|
while (1) {
|
||||||
|
if (ancestors_of_A.count(cursor))
|
||||||
|
return cursor;
|
||||||
|
if (cursor->NumOfRefs() != 1)
|
||||||
|
break;
|
||||||
|
cursor = ((Instance*)cursor->GetReferences()->GetLast())->Owner();
|
||||||
|
}
|
||||||
|
|
||||||
|
log_error("No common ancestor found between %s and %s.\n", get_full_netlist_name(A).c_str(), get_full_netlist_name(B).c_str());
|
||||||
|
}
|
||||||
|
|
||||||
void run(Netlist *nl)
|
void run(Netlist *nl)
|
||||||
{
|
{
|
||||||
MapIter mi, mi2;
|
MapIter mi, mi2;
|
||||||
|
@ -1674,19 +1712,37 @@ struct VerificExtNets
|
||||||
if (verific_verbose)
|
if (verific_verbose)
|
||||||
log("Fixing external net reference on port %s.%s.%s:\n", get_full_netlist_name(nl).c_str(), inst->Name(), port->Name());
|
log("Fixing external net reference on port %s.%s.%s:\n", get_full_netlist_name(nl).c_str(), inst->Name(), port->Name());
|
||||||
|
|
||||||
while (net->IsExternalTo(nl))
|
Netlist *ext_nl = net->Owner();
|
||||||
{
|
|
||||||
Net *newnet = get_net_level_up(net);
|
|
||||||
if (newnet == net) break;
|
|
||||||
|
|
||||||
|
if (verific_verbose)
|
||||||
|
log(" external net owner: %s\n", get_full_netlist_name(ext_nl).c_str());
|
||||||
|
|
||||||
|
Netlist *ca_nl = find_common_ancestor(nl, ext_nl);
|
||||||
|
|
||||||
|
if (verific_verbose)
|
||||||
|
log(" common ancestor: %s\n", get_full_netlist_name(ca_nl).c_str());
|
||||||
|
|
||||||
|
Net *ca_net = route_up(net, !port->IsOutput(), ca_nl);
|
||||||
|
Net *new_net = ca_net;
|
||||||
|
|
||||||
|
if (ca_nl != nl)
|
||||||
|
{
|
||||||
if (verific_verbose)
|
if (verific_verbose)
|
||||||
log(" external net: %s.%s\n", get_full_netlist_name(net->Owner()).c_str(), net->Name());
|
log(" net in common ancestor: %s\n", ca_net->Name());
|
||||||
net = newnet;
|
|
||||||
|
string name = stringf("___extnets_%d", portname_cnt++);
|
||||||
|
new_net = new Net(name.c_str());
|
||||||
|
nl->Add(new_net);
|
||||||
|
|
||||||
|
Net *n = route_up(new_net, port->IsOutput(), ca_nl, ca_net);
|
||||||
|
log_assert(n == ca_net);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (verific_verbose)
|
if (verific_verbose)
|
||||||
log(" final net: %s.%s%s\n", get_full_netlist_name(net->Owner()).c_str(), net->Name(), net->IsExternalTo(nl) ? " (external)" : "");
|
log(" new local net: %s\n", new_net->Name());
|
||||||
todo_connect.push_back(tuple<Instance*, Port*, Net*>(inst, port, net));
|
|
||||||
|
log_assert(!new_net->IsExternalTo(nl));
|
||||||
|
todo_connect.push_back(tuple<Instance*, Port*, Net*>(inst, port, new_net));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto it : todo_connect) {
|
for (auto it : todo_connect) {
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
module top(input i, output o);
|
||||||
|
A A();
|
||||||
|
B B();
|
||||||
|
assign A.i = i;
|
||||||
|
assign o = B.o;
|
||||||
|
always @* assert(o == i);
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module A;
|
||||||
|
wire i, y;
|
||||||
|
`ifdef FAIL
|
||||||
|
assign B.x = i;
|
||||||
|
`else
|
||||||
|
assign B.x = !i;
|
||||||
|
`endif
|
||||||
|
assign y = !B.y;
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module B;
|
||||||
|
wire x, y, o;
|
||||||
|
assign y = x, o = A.y;
|
||||||
|
endmodule
|
Loading…
Reference in New Issue