timing: Add clock skew to arrival and required time
This commit is contained in:
parent
60ee682d58
commit
fc3b2de8da
@ -116,10 +116,10 @@ delay_t Context::predictArcDelay(const NetInfo *net_info, const PortRef &sink) c
|
||||
|
||||
delay_t Context::getNetinfoRouteDelay(const NetInfo *net_info, const PortRef &user_info) const
|
||||
{
|
||||
#ifdef ARCH_ECP5
|
||||
if (net_info->is_global)
|
||||
return 0;
|
||||
#endif
|
||||
// #ifdef ARCH_ECP5
|
||||
// if (net_info->is_global)
|
||||
// return 0;
|
||||
// #endif
|
||||
|
||||
if (net_info->wires.empty())
|
||||
return predictArcDelay(net_info, user_info);
|
||||
@ -417,7 +417,7 @@ void Context::check() const
|
||||
namespace {
|
||||
struct FixupHierarchyWorker
|
||||
{
|
||||
FixupHierarchyWorker(Context *ctx) : ctx(ctx){};
|
||||
FixupHierarchyWorker(Context *ctx) : ctx(ctx) {};
|
||||
Context *ctx;
|
||||
void run()
|
||||
{
|
||||
|
@ -174,10 +174,20 @@ void TimingAnalyser::get_route_delays()
|
||||
NetInfo *ni = net.second.get();
|
||||
if (ni->driver.cell == nullptr || ni->driver.cell->bel == BelId())
|
||||
continue;
|
||||
|
||||
if (clock_skew) {
|
||||
printf("net %s has driver %s.%s\n", ni->name.c_str(ctx), ni->driver.cell->name.c_str(ctx),
|
||||
ni->driver.port.c_str(ctx));
|
||||
}
|
||||
for (auto &usr : ni->users) {
|
||||
if (usr.cell->bel == BelId())
|
||||
continue;
|
||||
ports.at(CellPortKey(usr)).route_delay = DelayPair(ctx->getNetinfoRouteDelay(ni, usr));
|
||||
|
||||
if (clock_skew) {
|
||||
printf("\tuser %s.%s, delay: %f\n", usr.cell->name.c_str(ctx), usr.port.c_str(ctx),
|
||||
ctx->getDelayNS(ctx->getNetinfoRouteDelay(ni, usr)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -567,12 +577,15 @@ void TimingAnalyser::walk_forward()
|
||||
auto &pd = ports.at(sp.first);
|
||||
DelayPair init_arrival(0);
|
||||
CellPortKey clock_key;
|
||||
// TODO: clock routing delay, if analysis of that is enabled
|
||||
if (sp.second != IdString()) {
|
||||
// clocked startpoints have a clock-to-out time
|
||||
for (auto &fanin : pd.cell_arcs) {
|
||||
if (fanin.type == CellArc::CLK_TO_Q && fanin.other_port == sp.second) {
|
||||
init_arrival = init_arrival + fanin.value.delayPair();
|
||||
init_arrival += fanin.value.delayPair();
|
||||
if (clock_skew) {
|
||||
auto clock_delay = ports.at(CellPortKey(sp.first.cell, fanin.other_port)).route_delay;
|
||||
init_arrival += clock_delay;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -619,20 +632,28 @@ void TimingAnalyser::walk_backward()
|
||||
auto &dom = domains.at(dom_id);
|
||||
for (auto &ep : dom.endpoints) {
|
||||
auto &pd = ports.at(ep.first);
|
||||
DelayPair init_setuphold(0);
|
||||
DelayPair init_required(0);
|
||||
CellPortKey clock_key;
|
||||
// TODO: clock routing delay, if analysis of that is enabled
|
||||
if (ep.second != IdString()) {
|
||||
// Add setup/hold time, if this endpoint is clocked
|
||||
for (auto &fanin : pd.cell_arcs) {
|
||||
if (fanin.type == CellArc::SETUP && fanin.other_port == ep.second)
|
||||
init_setuphold.min_delay -= fanin.value.maxDelay();
|
||||
printf("walk bwd %s.%s, fanin: %s, arctype: %s\n", ep.first.cell.c_str(ctx),
|
||||
ep.first.port.c_str(ctx), fanin.other_port.c_str(ctx), arcType_to_str(fanin.type).c_str());
|
||||
|
||||
if (fanin.type == CellArc::SETUP && fanin.other_port == ep.second) {
|
||||
if (clock_skew) {
|
||||
auto clock_delay = ports.at(CellPortKey(ep.first.cell, fanin.other_port)).route_delay;
|
||||
init_required += clock_delay;
|
||||
}
|
||||
init_required.min_delay -= fanin.value.maxDelay();
|
||||
}
|
||||
if (fanin.type == CellArc::HOLD && fanin.other_port == ep.second)
|
||||
init_setuphold.max_delay -= fanin.value.maxDelay();
|
||||
init_required.max_delay -= fanin.value.maxDelay();
|
||||
}
|
||||
clock_key = CellPortKey(ep.first.cell, ep.second);
|
||||
}
|
||||
set_required_time(ep.first, dom_id, init_setuphold, 1, clock_key);
|
||||
set_required_time(ep.first, dom_id, init_required, 1, clock_key);
|
||||
}
|
||||
}
|
||||
// Walk backwards in topological order
|
||||
@ -1211,6 +1232,8 @@ void timing_analysis(Context *ctx, bool print_slack_histogram, bool print_fmax,
|
||||
bool update_results)
|
||||
{
|
||||
TimingAnalyser tmg(ctx);
|
||||
tmg.setup_only = false;
|
||||
tmg.clock_skew = true;
|
||||
tmg.setup(ctx->detailed_timing_report, print_slack_histogram, print_path || print_fmax);
|
||||
|
||||
auto &result = tmg.get_timing_result();
|
||||
|
@ -98,6 +98,10 @@ struct TimingAnalyser
|
||||
|
||||
TimingResult &get_timing_result() { return result; }
|
||||
|
||||
// Enable analysis of clock skew between FFs.
|
||||
// Only do this after legal placement
|
||||
bool clock_skew = false;
|
||||
|
||||
bool setup_only = false;
|
||||
bool have_loops = false;
|
||||
bool updated_domains = false;
|
||||
|
Loading…
Reference in New Issue
Block a user