aboutsummaryrefslogtreecommitdiffstats
path: root/nexus
diff options
context:
space:
mode:
authorDavid Shah <dave@ds0.me>2020-11-10 11:01:30 +0000
committerDavid Shah <dave@ds0.me>2020-11-30 08:45:28 +0000
commit8c1f25cf31644c95e4ba0a1c2a2b212abd622167 (patch)
treebf9dda90da868c316a83f8a7ed0caa1b103bd415 /nexus
parent6457b4ca7b90c59a886ed623d321504131ebeeb6 (diff)
downloadnextpnr-8c1f25cf31644c95e4ba0a1c2a2b212abd622167.tar.gz
nextpnr-8c1f25cf31644c95e4ba0a1c2a2b212abd622167.tar.bz2
nextpnr-8c1f25cf31644c95e4ba0a1c2a2b212abd622167.zip
timing: Add a few more cell types
Signed-off-by: David Shah <dave@ds0.me>
Diffstat (limited to 'nexus')
-rw-r--r--nexus/arch.cc82
-rw-r--r--nexus/arch.h9
-rw-r--r--nexus/archdefs.h2
-rw-r--r--nexus/constids.inc1
-rw-r--r--nexus/pack.cc10
5 files changed, 97 insertions, 7 deletions
diff --git a/nexus/arch.cc b/nexus/arch.cc
index 78e10e16..b6181011 100644
--- a/nexus/arch.cc
+++ b/nexus/arch.cc
@@ -435,9 +435,23 @@ DecalXY Arch::getGroupDecal(GroupId pip) const { return {}; };
bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const
{
+ auto lookup_port = [&](IdString p) {
+ auto fnd = cell->tmg_portmap.find(p);
+ return fnd == cell->tmg_portmap.end() ? p : fnd->second;
+ };
if (cell->type == id_OXIDE_COMB) {
- if (toPort == id_F)
- return lookup_cell_delay(cell->tmg_index, fromPort, toPort, delay);
+ if (cell->lutInfo.is_carry) {
+ bool result = lookup_cell_delay(cell->tmg_index, lookup_port(fromPort), lookup_port(toPort), delay);
+ // Because CCU2 = 2x OXIDE_COMB
+ if (result && fromPort == id_FCI && toPort == id_FCO) {
+ delay.min_delay /= 2;
+ delay.max_delay /= 2;
+ }
+ return result;
+ } else {
+ if (toPort == id_F)
+ return lookup_cell_delay(cell->tmg_index, fromPort, toPort, delay);
+ }
}
return false;
}
@@ -446,20 +460,44 @@ TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, in
{
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)
+ if (port == id_A || port == id_B || port == id_C || port == id_D || port == id_FCI)
return TMG_COMB_INPUT;
- if (port == id_F) {
+ if (port == id_F || port == id_OFX || port == id_FCO) {
if (disconnected(id_A) && disconnected(id_B) && disconnected(id_C) && disconnected(id_D) &&
- disconnected(id_FCI))
+ disconnected(id_FCI) && disconnected(id_SEL))
return TMG_IGNORE;
else
return TMG_COMB_OUTPUT;
}
+ } else if (cell->type == id_OXIDE_FF) {
+ if (port == id_CLK)
+ return TMG_CLOCK_INPUT;
+ else if (port == id_Q) {
+ clockInfoCount = 1;
+ return TMG_REGISTER_OUTPUT;
+ } else {
+ clockInfoCount = 1;
+ return TMG_REGISTER_INPUT;
+ }
}
return TMG_IGNORE;
}
-TimingClockingInfo Arch::getPortClockingInfo(const CellInfo *cell, IdString port, int index) const { return {}; }
+TimingClockingInfo Arch::getPortClockingInfo(const CellInfo *cell, IdString port, int index) const
+{
+ TimingClockingInfo info;
+ if (cell->type == id_OXIDE_FF) {
+ info.edge = (cell->ffInfo.ctrlset.clkmux == ID_INV) ? FALLING_EDGE : RISING_EDGE;
+ info.clock_port = id_CLK;
+ if (port == id_Q)
+ NPNR_ASSERT(lookup_cell_delay(cell->tmg_index, id_CLK, port, info.clockToQ));
+ else
+ lookup_cell_setuphold(cell->tmg_index, port, id_CLK, info.setup, info.hold);
+ } else {
+ NPNR_ASSERT_FALSE("missing clocking info");
+ }
+ return info;
+}
// -----------------------------------------------------------------------
@@ -750,6 +788,38 @@ void Arch::lookup_cell_setuphold(int type_idx, IdString from_port, IdString cloc
[](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);
+ setup.min_delay = ct.setup_holds[dly_idx].min_setup;
+ setup.max_delay = ct.setup_holds[dly_idx].max_setup;
+ hold.min_delay = ct.setup_holds[dly_idx].min_hold;
+ hold.max_delay = ct.setup_holds[dly_idx].max_hold;
+}
+
+void Arch::lookup_cell_setuphold_clock(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 sh.sig_port; },
+ from_port.index);
+ NPNR_ASSERT(dly_idx != -1);
+ clock = IdString(ct.setup_holds[dly_idx].clock_port);
+ setup.min_delay = ct.setup_holds[dly_idx].min_setup;
+ setup.max_delay = ct.setup_holds[dly_idx].max_setup;
+ hold.min_delay = ct.setup_holds[dly_idx].min_hold;
+ hold.max_delay = ct.setup_holds[dly_idx].max_hold;
+}
+void Arch::lookup_cell_clock_out(int type_idx, IdString to_port, IdString &clock, 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 pd.to_port; },
+ to_port.index);
+ NPNR_ASSERT(dly_idx != -1);
+ clock = ct.prop_delays[dly_idx].from_port;
+ delay.min_delay = ct.prop_delays[dly_idx].min_delay;
+ delay.max_delay = ct.prop_delays[dly_idx].max_delay;
}
// -----------------------------------------------------------------------
diff --git a/nexus/arch.h b/nexus/arch.h
index cbe39316..9b75a09e 100644
--- a/nexus/arch.h
+++ b/nexus/arch.h
@@ -1547,10 +1547,19 @@ struct Arch : BaseCtx
// -------------------------------------------------
// Cell timing lookup helpers
+
+ // Given cell type and variant, get the index inside the speed grade timing data
int get_cell_timing_idx(IdString cell_type, IdString cell_variant = IdString()) const;
+ // Return true and set delay if a comb path exists in a given cell timing index
bool lookup_cell_delay(int type_idx, IdString from_port, IdString to_port, DelayInfo &delay) const;
+ // Get setup and hold time for a given cell timing index and signal/clock pair
void lookup_cell_setuphold(int type_idx, IdString from_port, IdString clock, DelayInfo &setup,
DelayInfo &hold) const;
+ // Get setup and hold time and associated clock for a given cell timing index and signal
+ void lookup_cell_setuphold_clock(int type_idx, IdString from_port, IdString &clock, DelayInfo &setup,
+ DelayInfo &hold) const;
+ // Similar to lookup_cell_delay but only needs the 'to' signal, intended for clk->out delays
+ void lookup_cell_clock_out(int type_idx, IdString to_port, IdString &clock, DelayInfo &delay) const;
// -------------------------------------------------
// List of IO constraints, used by PDC parser
diff --git a/nexus/archdefs.h b/nexus/archdefs.h
index 8925c5f3..adc1342c 100644
--- a/nexus/archdefs.h
+++ b/nexus/archdefs.h
@@ -188,6 +188,8 @@ struct ArchCellInfo
};
int tmg_index = -1;
+ // Map from cell/bel ports to logical timing ports
+ std::unordered_map<IdString, IdString> tmg_portmap;
};
NEXTPNR_NAMESPACE_END
diff --git a/nexus/constids.inc b/nexus/constids.inc
index 2ac2349c..b4d53265 100644
--- a/nexus/constids.inc
+++ b/nexus/constids.inc
@@ -90,6 +90,7 @@ X(CIN)
X(COUT)
X(S0)
X(S1)
+X(F0)
X(CLKMUX)
X(CEMUX)
diff --git a/nexus/pack.cc b/nexus/pack.cc
index 5dcfd9e2..481dcbf6 100644
--- a/nexus/pack.cc
+++ b/nexus/pack.cc
@@ -1264,7 +1264,14 @@ void Arch::assignCellInfo(CellInfo *cell)
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);
+ cell->tmg_index = get_cell_timing_idx(id_OXIDE_COMB, cell->lutInfo.is_carry ? id_CCU2 : id_LUT4);
+ if (cell->lutInfo.is_carry) {
+ cell->tmg_portmap[id_A] = id_A0;
+ cell->tmg_portmap[id_B] = id_B0;
+ cell->tmg_portmap[id_C] = id_C0;
+ cell->tmg_portmap[id_D] = id_D0;
+ cell->tmg_portmap[id_F] = id_F0;
+ }
} 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);
@@ -1277,6 +1284,7 @@ void Arch::assignCellInfo(CellInfo *cell)
cell->ffInfo.ctrlset.lsr = get_net_or_empty(cell, id_LSR);
cell->ffInfo.di = get_net_or_empty(cell, id_DI);
cell->ffInfo.m = get_net_or_empty(cell, id_M);
+ cell->tmg_index = get_cell_timing_idx(id_OXIDE_FF, id("PPP:SYNC"));
} else if (cell->type == id_RAMW) {
cell->ffInfo.ctrlset.async = true;
cell->ffInfo.ctrlset.regddr_en = false;