diff --git a/common/kernel/arch_pybindings_shared.h b/common/kernel/arch_pybindings_shared.h index ac0eda07..4598a41d 100644 --- a/common/kernel/arch_pybindings_shared.h +++ b/common/kernel/arch_pybindings_shared.h @@ -19,6 +19,8 @@ fn_wrapper_1a>::def_wrap(ctx_cls, "getNetByAlias"); fn_wrapper_2a_v, pass_through>::def_wrap(ctx_cls, "addClock"); +fn_wrapper_1a_v>::def_wrap( + ctx_cls, "ignoreTiming"); fn_wrapper_5a_v, pass_through, pass_through, pass_through, pass_through>::def_wrap(ctx_cls, "createRectangularRegion"); diff --git a/common/kernel/basectx.cc b/common/kernel/basectx.cc index 3009c26c..af9de72d 100644 --- a/common/kernel/basectx.cc +++ b/common/kernel/basectx.cc @@ -111,6 +111,19 @@ void BaseCtx::addClock(IdString net, float freq) log_info("constraining clock net '%s' to %.02f MHz\n", net.c_str(this), freq); } +void BaseCtx::ignoreTiming(IdString net) +{ + if (net_aliases.count(net)) { + getNetByAlias(net)->ignore_timing = true; + } else if (ports.count(net)) { + ports[net].net->ignore_timing = true; + } else { + log_warning("net '%s' does not exist in design, ignoring timing bypass constraint\n", net.c_str(this)); + return; + } + log_info("ignoring timing on net '%s'\n", net.c_str(this)); +} + void BaseCtx::createRectangularRegion(IdString name, int x0, int y0, int x1, int y1) { std::unique_ptr new_region(new Region()); diff --git a/common/kernel/basectx.h b/common/kernel/basectx.h index 3f021e82..5cf89e60 100644 --- a/common/kernel/basectx.h +++ b/common/kernel/basectx.h @@ -222,6 +222,7 @@ struct BaseCtx // Intended to simplify Python API void addClock(IdString net, float freq); + void ignoreTiming(IdString net); void createRectangularRegion(IdString name, int x0, int y0, int x1, int y1); void addBelToRegion(IdString name, BelId bel); void constrainCellToRegion(IdString cell, IdString region_name); diff --git a/common/kernel/nextpnr_types.h b/common/kernel/nextpnr_types.h index 5ee030b1..2a60e480 100644 --- a/common/kernel/nextpnr_types.h +++ b/common/kernel/nextpnr_types.h @@ -179,6 +179,7 @@ struct NetInfo : ArchNetInfo std::vector aliases; // entries in net_aliases that point to this net std::unique_ptr clkconstr; + bool ignore_timing = false; Region *region = nullptr; }; diff --git a/common/kernel/timing.cc b/common/kernel/timing.cc index fa8959a9..b4296e89 100644 --- a/common/kernel/timing.cc +++ b/common/kernel/timing.cc @@ -107,6 +107,8 @@ void TimingAnalyser::get_cell_delays() pd.cell_arcs.clear(); int clkInfoCount = 0; TimingPortClass cls = ctx->getPortTimingClass(ci, name, clkInfoCount); + if (pi.net->ignore_timing) + continue; if (cls == TMG_CLOCK_INPUT || cls == TMG_GEN_CLOCK || cls == TMG_IGNORE) continue; if (pi.type == PORT_IN) { diff --git a/docs/constraints.md b/docs/constraints.md index dead8780..e7bb719f 100644 --- a/docs/constraints.md +++ b/docs/constraints.md @@ -42,3 +42,8 @@ calling the function `ctx.addClock` with the name of the clock and its frequency ctx.addClock("video_clk", 24) ctx.addClock("uart_i.sys_clk_i", 12) +## Timing Constraints + +A net can be removed from the timing analysis using the Python API function `ctx.ignoreTiming`, as described above. + + ctx.ignoreTiming("module_inst.slow_net") diff --git a/docs/netlist.md b/docs/netlist.md index 6cff4a25..4a007a05 100644 --- a/docs/netlist.md +++ b/docs/netlist.md @@ -52,6 +52,7 @@ It also implements functions for getting timing data, mirroring that of the Arch - Manipulation of this structure is done automatically by `Arch::bindWire`, `Arch::unbindWire`, `Arch::bindPip` and `Arch::unbindPip`; which should almost always be used in lieu of manual manipulation - `attrs` stores metadata about the wire (which may come from the JSON or be added by passes) - `clkconstr` contains the period constraint if the wire is a constrained clock; or is empty otherwise + - `ignore_timing` is true if the net should be excluded from timing analysis - `region` is a reference to a `Region` if the net is constrained to a device region or `nullptr` otherwise (_N.B. not supported by the current router_). ## BaseCtx/Context