diff options
author | David Shah <dave@ds0.me> | 2020-11-09 16:06:40 +0000 |
---|---|---|
committer | David Shah <dave@ds0.me> | 2020-11-30 08:45:28 +0000 |
commit | fa9194e3e2212ef265b94b1be58da7c59d9a0bbf (patch) | |
tree | bd4c0827720012d8a14b3f7ef9f3aca92763a315 | |
parent | 963fd175ad69c5468bfc486e789cf6c7ff85f57e (diff) | |
download | nextpnr-fa9194e3e2212ef265b94b1be58da7c59d9a0bbf.tar.gz nextpnr-fa9194e3e2212ef265b94b1be58da7c59d9a0bbf.tar.bz2 nextpnr-fa9194e3e2212ef265b94b1be58da7c59d9a0bbf.zip |
nexus: Add cell delay lookup
Signed-off-by: David Shah <dave@ds0.me>
-rw-r--r-- | nexus/arch.cc | 81 | ||||
-rw-r--r-- | nexus/arch.h | 6 | ||||
-rw-r--r-- | nexus/archdefs.h | 2 | ||||
-rw-r--r-- | nexus/pack.cc | 2 |
4 files changed, 91 insertions, 0 deletions
diff --git a/nexus/arch.cc b/nexus/arch.cc index aff00d5d..a25fc95e 100644 --- a/nexus/arch.cc +++ b/nexus/arch.cc @@ -435,11 +435,27 @@ DecalXY Arch::getGroupDecal(GroupId pip) const { return {}; }; bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const { + if (cell->type == id_OXIDE_COMB) { + if (toPort == id_F) + return lookup_cell_delay(cell->tmg_index, fromPort, toPort, delay); + } return false; } TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, int &clockInfoCount) const { + auto disconnected = [cell](IdString p) { return !cell->ports.count(p) || cell->ports.at(p).net == nullptr; }; + if (cell->type == id_OXIDE_COMB) { + if (port == id_A || port == id_B || port == id_C || port == id_D) + return TMG_COMB_INPUT; + if (port == id_F) { + if (disconnected(id_A) && disconnected(id_B) && disconnected(id_C) && disconnected(id_D) && + disconnected(id_FCI)) + return TMG_IGNORE; + else + return TMG_COMB_OUTPUT; + } + } return TMG_IGNORE; } @@ -673,6 +689,71 @@ std::string Arch::get_pad_functions(const PadInfoPOD *pad) const // ----------------------------------------------------------------------- +// Helper for cell timing lookups +namespace { +template <typename Tres, typename Tgetter, typename Tkey> +int db_binary_search(const Tres *list, int count, Tgetter key_getter, Tkey key) +{ + if (count < 7) { + for (int i = 0; i < count; i++) { + if (key_getter(list[i]) == key) { + return i; + } + } + } else { + int b = 0, e = count - 1; + while (b <= e) { + int i = (b + e) / 2; + if (key_getter(list[i]) == key) { + return i; + } + if (key_getter(list[i]) > key) + e = i - 1; + else + b = i + 1; + } + } + return -1; +} +} // namespace + +int Arch::get_cell_timing_idx(IdString cell_type, IdString cell_variant) const +{ + return db_binary_search( + speed_grade->cell_types.get(), speed_grade->num_cell_types, + [](const CellTimingPOD &ct) { return std::make_pair(ct.cell_type, ct.cell_variant); }, + std::make_pair(cell_type.index, cell_variant.index)); +} + +bool Arch::lookup_cell_delay(int type_idx, IdString from_port, IdString to_port, DelayInfo &delay) const +{ + NPNR_ASSERT(type_idx != -1); + const auto &ct = speed_grade->cell_types[type_idx]; + int dly_idx = db_binary_search( + ct.prop_delays.get(), ct.num_prop_delays, + [](const CellPropDelayPOD &pd) { return std::make_pair(pd.from_port, pd.to_port); }, + std::make_pair(from_port.index, to_port.index)); + if (dly_idx == -1) + return false; + delay.min_delay = ct.prop_delays[dly_idx].min_delay; + delay.max_delay = ct.prop_delays[dly_idx].max_delay; + return true; +} + +void Arch::lookup_cell_setuphold(int type_idx, IdString from_port, IdString clock, DelayInfo &setup, + DelayInfo &hold) const +{ + NPNR_ASSERT(type_idx != -1); + const auto &ct = speed_grade->cell_types[type_idx]; + int dly_idx = db_binary_search( + ct.setup_holds.get(), ct.num_setup_holds, + [](const CellSetupHoldPOD &sh) { return std::make_pair(sh.sig_port, sh.clock_port); }, + std::make_pair(from_port.index, clock.index)); + NPNR_ASSERT(dly_idx != -1); +} + +// ----------------------------------------------------------------------- + #ifdef WITH_HEAP const std::string Arch::defaultPlacer = "heap"; #else diff --git a/nexus/arch.h b/nexus/arch.h index 93272af8..2d68ebeb 100644 --- a/nexus/arch.h +++ b/nexus/arch.h @@ -1546,6 +1546,12 @@ struct Arch : BaseCtx bool is_io_type_ref(const std::string &io_type) const; // ------------------------------------------------- + // Cell timing lookup helpers + int get_cell_timing_idx(IdString cell_type, IdString cell_variant = IdString()) const; + bool lookup_cell_delay(int type_idx, IdString from_port, IdString to_port, DelayInfo &delay) const; + void lookup_cell_setuphold(int type_idx, IdString from_port, IdString clock, DelayInfo &setup, + DelayInfo &hold) const; + // ------------------------------------------------- // List of IO constraints, used by PDC parser std::unordered_map<IdString, std::unordered_map<IdString, Property>> io_attr; diff --git a/nexus/archdefs.h b/nexus/archdefs.h index cdf15825..8925c5f3 100644 --- a/nexus/archdefs.h +++ b/nexus/archdefs.h @@ -186,6 +186,8 @@ struct ArchCellInfo NetInfo *di, *m; } ffInfo; }; + + int tmg_index = -1; }; NEXTPNR_NAMESPACE_END diff --git a/nexus/pack.cc b/nexus/pack.cc index c085c5ee..5dcfd9e2 100644 --- a/nexus/pack.cc +++ b/nexus/pack.cc @@ -1257,12 +1257,14 @@ void Arch::assignArchInfo() void Arch::assignCellInfo(CellInfo *cell) { + cell->tmg_index = -1; if (cell->type == id_OXIDE_COMB) { cell->lutInfo.is_memory = str_or_default(cell->params, id_MODE, "LOGIC") == "DPRAM"; cell->lutInfo.is_carry = str_or_default(cell->params, id_MODE, "LOGIC") == "CCU2"; cell->lutInfo.mux2_used = port_used(cell, id_OFX); cell->lutInfo.f = get_net_or_empty(cell, id_F); cell->lutInfo.ofx = get_net_or_empty(cell, id_OFX); + cell->tmg_index = get_cell_timing_idx(id_OXIDE_COMB, id_LUT4); } else if (cell->type == id_OXIDE_FF) { cell->ffInfo.ctrlset.async = str_or_default(cell->params, id_SRMODE, "LSR_OVER_CE") == "ASYNC"; cell->ffInfo.ctrlset.regddr_en = is_enabled(cell, id_REGDDR); |