timing: Fix domain init when loops are present
Signed-off-by: gatecat <gatecat@ds0.me>
This commit is contained in:
parent
5cd2a7f9c2
commit
ece10c3e04
129
common/timing.cc
129
common/timing.cc
@ -185,6 +185,7 @@ void TimingAnalyser::topo_sort()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
have_loops = !no_loops;
|
||||||
std::swap(topological_order, topo.sorted);
|
std::swap(topological_order, topo.sorted);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -195,66 +196,77 @@ void TimingAnalyser::setup_port_domains()
|
|||||||
d.endpoints.clear();
|
d.endpoints.clear();
|
||||||
}
|
}
|
||||||
// Go forward through the topological order (domains from the PoV of arrival time)
|
// Go forward through the topological order (domains from the PoV of arrival time)
|
||||||
for (auto port : topological_order) {
|
bool first_iter = true;
|
||||||
auto &pd = ports.at(port);
|
do {
|
||||||
auto &pi = port_info(port);
|
updated_domains = false;
|
||||||
if (pi.type == PORT_OUT) {
|
for (auto port : topological_order) {
|
||||||
for (auto &fanin : pd.cell_arcs) {
|
auto &pd = ports.at(port);
|
||||||
if (fanin.type != CellArc::CLK_TO_Q)
|
auto &pi = port_info(port);
|
||||||
continue;
|
if (pi.type == PORT_OUT) {
|
||||||
// registered outputs are startpoints
|
if (first_iter) {
|
||||||
auto dom = domain_id(port.cell, fanin.other_port, fanin.edge);
|
for (auto &fanin : pd.cell_arcs) {
|
||||||
// create per-domain data
|
if (fanin.type != CellArc::CLK_TO_Q)
|
||||||
pd.arrival[dom];
|
continue;
|
||||||
domains.at(dom).startpoints.emplace_back(port, fanin.other_port);
|
// registered outputs are startpoints
|
||||||
}
|
auto dom = domain_id(port.cell, fanin.other_port, fanin.edge);
|
||||||
// copy domains across routing
|
// create per-domain data
|
||||||
if (pi.net != nullptr)
|
pd.arrival[dom];
|
||||||
for (auto &usr : pi.net->users)
|
domains.at(dom).startpoints.emplace_back(port, fanin.other_port);
|
||||||
copy_domains(port, CellPortKey(usr), false);
|
}
|
||||||
} else {
|
}
|
||||||
// copy domains from input to output
|
// copy domains across routing
|
||||||
for (auto &fanout : pd.cell_arcs) {
|
if (pi.net != nullptr)
|
||||||
if (fanout.type != CellArc::COMBINATIONAL)
|
for (auto &usr : pi.net->users)
|
||||||
continue;
|
copy_domains(port, CellPortKey(usr), false);
|
||||||
copy_domains(port, CellPortKey(port.cell, fanout.other_port), false);
|
} else {
|
||||||
|
// copy domains from input to output
|
||||||
|
for (auto &fanout : pd.cell_arcs) {
|
||||||
|
if (fanout.type != CellArc::COMBINATIONAL)
|
||||||
|
continue;
|
||||||
|
copy_domains(port, CellPortKey(port.cell, fanout.other_port), false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
// Go backward through the topological order (domains from the PoV of required time)
|
||||||
// Go backward through the topological order (domains from the PoV of required time)
|
for (auto port : reversed_range(topological_order)) {
|
||||||
for (auto port : reversed_range(topological_order)) {
|
auto &pd = ports.at(port);
|
||||||
auto &pd = ports.at(port);
|
auto &pi = port_info(port);
|
||||||
auto &pi = port_info(port);
|
if (pi.type == PORT_OUT) {
|
||||||
if (pi.type == PORT_OUT) {
|
// copy domains from output to input
|
||||||
// copy domains from output to input
|
for (auto &fanin : pd.cell_arcs) {
|
||||||
for (auto &fanin : pd.cell_arcs) {
|
if (fanin.type != CellArc::COMBINATIONAL)
|
||||||
if (fanin.type != CellArc::COMBINATIONAL)
|
continue;
|
||||||
continue;
|
copy_domains(port, CellPortKey(port.cell, fanin.other_port), true);
|
||||||
copy_domains(port, CellPortKey(port.cell, fanin.other_port), true);
|
}
|
||||||
|
} else {
|
||||||
|
if (first_iter) {
|
||||||
|
for (auto &fanout : pd.cell_arcs) {
|
||||||
|
if (fanout.type != CellArc::SETUP)
|
||||||
|
continue;
|
||||||
|
// registered inputs are endpoints
|
||||||
|
auto dom = domain_id(port.cell, fanout.other_port, fanout.edge);
|
||||||
|
// create per-domain data
|
||||||
|
pd.required[dom];
|
||||||
|
domains.at(dom).endpoints.emplace_back(port, fanout.other_port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// copy port to driver
|
||||||
|
if (pi.net != nullptr && pi.net->driver.cell != nullptr)
|
||||||
|
copy_domains(port, CellPortKey(pi.net->driver), true);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
for (auto &fanout : pd.cell_arcs) {
|
|
||||||
if (fanout.type != CellArc::SETUP)
|
|
||||||
continue;
|
|
||||||
// registered inputs are startpoints
|
|
||||||
auto dom = domain_id(port.cell, fanout.other_port, fanout.edge);
|
|
||||||
// create per-domain data
|
|
||||||
pd.required[dom];
|
|
||||||
domains.at(dom).endpoints.emplace_back(port, fanout.other_port);
|
|
||||||
}
|
|
||||||
// copy port to driver
|
|
||||||
if (pi.net != nullptr && pi.net->driver.cell != nullptr)
|
|
||||||
copy_domains(port, CellPortKey(pi.net->driver), true);
|
|
||||||
}
|
}
|
||||||
}
|
// Iterate over ports and find domain paris
|
||||||
// Iterate over ports and find domain paris
|
for (auto port : topological_order) {
|
||||||
for (auto port : topological_order) {
|
auto &pd = ports.at(port);
|
||||||
auto &pd = ports.at(port);
|
for (auto &arr : pd.arrival)
|
||||||
for (auto &arr : pd.arrival)
|
for (auto &req : pd.required) {
|
||||||
for (auto &req : pd.required) {
|
pd.domain_pairs[domain_pair_id(arr.first, req.first)];
|
||||||
pd.domain_pairs[domain_pair_id(arr.first, req.first)];
|
}
|
||||||
}
|
}
|
||||||
}
|
first_iter = false;
|
||||||
|
// If there are loops, repeat the process until a fixed point is reached, as there might be unusual ways to
|
||||||
|
// visit points, which would result in a missing domain key and therefore crash later on
|
||||||
|
} while (have_loops && updated_domains);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TimingAnalyser::reset_times()
|
void TimingAnalyser::reset_times()
|
||||||
@ -561,8 +573,9 @@ domain_id_t TimingAnalyser::domain_pair_id(domain_id_t launch, domain_id_t captu
|
|||||||
void TimingAnalyser::copy_domains(const CellPortKey &from, const CellPortKey &to, bool backward)
|
void TimingAnalyser::copy_domains(const CellPortKey &from, const CellPortKey &to, bool backward)
|
||||||
{
|
{
|
||||||
auto &f = ports.at(from), &t = ports.at(to);
|
auto &f = ports.at(from), &t = ports.at(to);
|
||||||
for (auto &dom : (backward ? f.required : f.arrival))
|
for (auto &dom : (backward ? f.required : f.arrival)) {
|
||||||
(backward ? t.required : t.arrival)[dom.first];
|
updated_domains |= (backward ? t.required : t.arrival).emplace(dom.first, ArrivReqTime{}).second;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CellInfo *TimingAnalyser::cell_info(const CellPortKey &key) { return ctx->cells.at(key.cell).get(); }
|
CellInfo *TimingAnalyser::cell_info(const CellPortKey &key) { return ctx->cells.at(key.cell).get(); }
|
||||||
|
@ -142,6 +142,8 @@ struct TimingAnalyser
|
|||||||
|
|
||||||
bool setup_only = false;
|
bool setup_only = false;
|
||||||
bool verbose_mode = false;
|
bool verbose_mode = false;
|
||||||
|
bool have_loops = false;
|
||||||
|
bool updated_domains = false;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void init_ports();
|
void init_ports();
|
||||||
|
Loading…
Reference in New Issue
Block a user