aboutsummaryrefslogtreecommitdiffstats
path: root/ecp5/arch_place.cc
diff options
context:
space:
mode:
authorgatecat <gatecat@ds0.me>2022-03-31 11:17:57 +0100
committergatecat <gatecat@ds0.me>2022-04-07 18:02:36 +0100
commitefb58711b0dfcdb8080f63bd64d3f9d9fafd2637 (patch)
treea2b876f5cacc69125bdb2fbdc171517c6fb969c9 /ecp5/arch_place.cc
parentc4e47ba1a85d840c31d4be5c3f2c032664abd814 (diff)
downloadnextpnr-efb58711b0dfcdb8080f63bd64d3f9d9fafd2637.tar.gz
nextpnr-efb58711b0dfcdb8080f63bd64d3f9d9fafd2637.tar.bz2
nextpnr-efb58711b0dfcdb8080f63bd64d3f9d9fafd2637.zip
ecp5: Split the SLICE bel into separate LUT/FF/RAMW bels
Diffstat (limited to 'ecp5/arch_place.cc')
-rw-r--r--ecp5/arch_place.cc237
1 files changed, 138 insertions, 99 deletions
diff --git a/ecp5/arch_place.cc b/ecp5/arch_place.cc
index b1849ee6..afe9aca0 100644
--- a/ecp5/arch_place.cc
+++ b/ecp5/arch_place.cc
@@ -33,53 +33,156 @@ inline NetInfo *port_or_nullptr(const CellInfo *cell, IdString name)
return found->second.net;
}
-bool Arch::slices_compatible(const std::vector<const CellInfo *> &cells) const
+bool Arch::slices_compatible(LogicTileStatus *lts) const
{
- // TODO: allow different LSR/CLK and MUX/SRMODE settings once
- // routing details are worked out
- IdString clk_sig, lsr_sig;
- IdString CLKMUX, LSRMUX, SRMODE;
- bool first = true;
- for (auto cell : cells) {
- if (cell->sliceInfo.using_dff) {
- if (first) {
- clk_sig = cell->sliceInfo.clk_sig;
- lsr_sig = cell->sliceInfo.lsr_sig;
- CLKMUX = cell->sliceInfo.clkmux;
- LSRMUX = cell->sliceInfo.lsrmux;
- SRMODE = cell->sliceInfo.srmode;
- } else {
- if (cell->sliceInfo.clk_sig != clk_sig)
- return false;
- if (cell->sliceInfo.lsr_sig != lsr_sig)
- return false;
- if (cell->sliceInfo.clkmux != CLKMUX)
+ if (lts == nullptr)
+ return true;
+ for (int sl = 0; sl < 4; sl++) {
+ if (!lts->slices[sl].dirty) {
+ if (!lts->slices[sl].valid)
+ return false;
+ continue;
+ }
+ lts->slices[sl].dirty = false;
+ lts->slices[sl].valid = false;
+ bool found_ff = false;
+ uint8_t last_ff_flags = 0;
+ IdString last_ce_sig;
+ bool ramw_used = false;
+ if (sl == 2 && lts->cells[((sl * 2) << lc_idx_shift) | BEL_RAMW] != nullptr)
+ ramw_used = true;
+ for (int l = 0; l < 2; l++) {
+ bool comb_m_used = false;
+ CellInfo *comb = lts->cells[((sl * 2 + l) << lc_idx_shift) | BEL_COMB];
+ if (comb != nullptr) {
+ uint8_t flags = comb->combInfo.flags;
+ if (ramw_used && !(flags & ArchCellInfo::COMB_RAMW_BLOCK))
return false;
- if (cell->sliceInfo.lsrmux != LSRMUX)
+ if (flags & ArchCellInfo::COMB_MUX5) {
+ // MUX5 uses M signal and must be in LC 0
+ comb_m_used = true;
+ if (l != 0)
+ return false;
+ }
+ if (flags & ArchCellInfo::COMB_MUX6) {
+ // MUX6+ uses M signal and must be in LC 1
+ comb_m_used = true;
+ if (l != 1)
+ return false;
+ if (comb->combInfo.mux_fxad != nullptr &&
+ (comb->combInfo.mux_fxad->combInfo.flags & ArchCellInfo::COMB_MUX5)) {
+ // LUT6 structure must be rooted at SLICE 0 or 2
+ if (sl != 0 && sl != 2)
+ return false;
+ }
+ }
+ // LUTRAM must be in bottom two SLICEs only
+ if ((flags & ArchCellInfo::COMB_LUTRAM) && (sl > 1))
return false;
- if (cell->sliceInfo.srmode != SRMODE)
+ if (l == 1) {
+ // Carry usage must be the same for LCs 0 and 1 in a SLICE
+ CellInfo *comb0 = lts->cells[((sl * 2 + 0) << lc_idx_shift) | BEL_COMB];
+ if (comb0 &&
+ ((comb0->combInfo.flags & ArchCellInfo::COMB_CARRY) != (flags & ArchCellInfo::COMB_CARRY)))
+ return false;
+ }
+ }
+
+ CellInfo *ff = lts->cells[((sl * 2 + l) << lc_idx_shift) | BEL_FF];
+ if (ff != nullptr) {
+ uint8_t flags = ff->ffInfo.flags;
+ if (comb_m_used && (flags & ArchCellInfo::FF_M_USED))
return false;
+ if (found_ff) {
+ if ((flags & ArchCellInfo::FF_GSREN) != (last_ff_flags & ArchCellInfo::FF_GSREN))
+ return false;
+ if ((flags & ArchCellInfo::FF_CECONST) != (last_ff_flags & ArchCellInfo::FF_CECONST))
+ return false;
+ if ((flags & ArchCellInfo::FF_CEINV) != (last_ff_flags & ArchCellInfo::FF_CEINV))
+ return false;
+ if (ff->ffInfo.ce_sig != last_ce_sig)
+ return false;
+ } else {
+ found_ff = true;
+ last_ff_flags = flags;
+ last_ce_sig = ff->ffInfo.ce_sig;
+ }
+ }
+ }
+
+ lts->slices[sl].valid = true;
+ }
+ if (lts->tile_dirty) {
+ bool found_global_ff = false;
+ bool found_global_dpram = false;
+ bool global_lsrinv = false;
+ bool global_clkinv = false;
+ bool global_async = false;
+
+ IdString clk_sig, lsr_sig;
+
+ lts->tile_dirty = false;
+ lts->tile_valid = false;
+
+#define CHECK_EQUAL(x, y) \
+ do { \
+ if ((x) != (y)) \
+ return false; \
+ } while (0)
+ for (int i = 0; i < 8; i++) {
+ if (i < 4) {
+ // DPRAM
+ CellInfo *comb = lts->cells[(i << lc_idx_shift) | BEL_COMB];
+ if (comb != nullptr && (comb->combInfo.flags & ArchCellInfo::COMB_LUTRAM)) {
+ if (found_global_dpram) {
+ CHECK_EQUAL(bool(comb->combInfo.flags & ArchCellInfo::COMB_RAM_WCKINV), global_clkinv);
+ CHECK_EQUAL(bool(comb->combInfo.flags & ArchCellInfo::COMB_RAM_WREINV), global_lsrinv);
+ } else {
+ global_clkinv = bool(comb->combInfo.flags & ArchCellInfo::COMB_RAM_WCKINV);
+ global_lsrinv = bool(comb->combInfo.flags & ArchCellInfo::COMB_RAM_WREINV);
+ found_global_dpram = true;
+ }
+ }
+ }
+ // FF
+ CellInfo *ff = lts->cells[(i << lc_idx_shift) | BEL_FF];
+ if (ff != nullptr) {
+ if (found_global_dpram) {
+ CHECK_EQUAL(bool(ff->ffInfo.flags & ArchCellInfo::FF_CLKINV), global_clkinv);
+ CHECK_EQUAL(bool(ff->ffInfo.flags & ArchCellInfo::FF_LSRINV), global_lsrinv);
+ }
+ if (found_global_ff) {
+ CHECK_EQUAL(ff->ffInfo.clk_sig, clk_sig);
+ CHECK_EQUAL(ff->ffInfo.lsr_sig, lsr_sig);
+ CHECK_EQUAL(bool(ff->ffInfo.flags & ArchCellInfo::FF_CLKINV), global_clkinv);
+ CHECK_EQUAL(bool(ff->ffInfo.flags & ArchCellInfo::FF_LSRINV), global_lsrinv);
+ CHECK_EQUAL(bool(ff->ffInfo.flags & ArchCellInfo::FF_ASYNC), global_async);
+
+ } else {
+ clk_sig = ff->ffInfo.clk_sig;
+ lsr_sig = ff->ffInfo.lsr_sig;
+ global_clkinv = bool(ff->ffInfo.flags & ArchCellInfo::FF_CLKINV);
+ global_lsrinv = bool(ff->ffInfo.flags & ArchCellInfo::FF_LSRINV);
+ global_async = bool(ff->ffInfo.flags & ArchCellInfo::FF_ASYNC);
+ found_global_ff = true;
+ }
}
- first = false;
}
+#undef CHECK_EQUAL
+ lts->tile_valid = true;
+ } else {
+ if (!lts->tile_valid)
+ return false;
}
+
return true;
}
bool Arch::isBelLocationValid(BelId bel) const
{
- if (getBelType(bel) == id_TRELLIS_SLICE) {
- std::vector<const CellInfo *> bel_cells;
- Loc bel_loc = getBelLocation(bel);
- for (auto bel_other : getBelsByTile(bel_loc.x, bel_loc.y)) {
- CellInfo *cell_other = getBoundBelCell(bel_other);
- if (cell_other != nullptr) {
- bel_cells.push_back(cell_other);
- }
- }
- if (getBoundBelCell(bel) != nullptr && getBoundBelCell(bel)->sliceInfo.has_l6mux && ((bel_loc.z % 2) == 1))
- return false;
- return slices_compatible(bel_cells);
+ IdString bel_type = getBelType(bel);
+ if (bel_type.in(id_TRELLIS_COMB, id_TRELLIS_FF, id_TRELLIS_RAMW)) {
+ return slices_compatible(tile_status.at(tile_index(bel)).lts);
} else {
CellInfo *cell = getBoundBelCell(bel);
if (cell == nullptr) {
@@ -93,70 +196,6 @@ bool Arch::isBelLocationValid(BelId bel) const
}
}
-void Arch::permute_luts()
-{
- TimingAnalyser tmg(getCtx());
- tmg.setup();
-
- auto proc_lut = [&](CellInfo *ci, int lut) {
- std::vector<IdString> port_names;
- for (int i = 0; i < 4; i++)
- port_names.push_back(id(std::string("ABCD").substr(i, 1) + std::to_string(lut)));
-
- std::vector<std::pair<float, int>> inputs;
- std::vector<NetInfo *> orig_nets;
-
- for (int i = 0; i < 4; i++) {
- if (!ci->ports.count(port_names.at(i))) {
- ci->ports[port_names.at(i)].name = port_names.at(i);
- ci->ports[port_names.at(i)].type = PORT_IN;
- }
- auto &port = ci->ports.at(port_names.at(i));
- float crit = (port.net == nullptr) ? 0 : tmg.get_criticality(CellPortKey(ci->name, port_names.at(i)));
- orig_nets.push_back(port.net);
- inputs.emplace_back(crit, i);
- }
- // Least critical first (A input is slowest)
-
- // Avoid permuting locked LUTs (e.g. from an OOC submodule)
- if (ci->belStrength <= STRENGTH_STRONG)
- std::sort(inputs.begin(), inputs.end());
- for (int i = 0; i < 4; i++) {
- IdString p = port_names.at(i);
- // log_info("%s %s %f\n", p.c_str(ctx), port_names.at(inputs.at(i).second).c_str(ctx), inputs.at(i).first);
- ci->disconnectPort(p);
- ci->ports.at(p).net = nullptr;
- if (orig_nets.at(inputs.at(i).second) != nullptr) {
- ci->connectPort(p, orig_nets.at(inputs.at(i).second));
- ci->params[id(p.str(this) + "MUX")] = p.str(this);
- } else {
- ci->params[id(p.str(this) + "MUX")] = std::string("1");
- }
- }
- // Rewrite function
- int old_init = int_or_default(ci->params, id("LUT" + std::to_string(lut) + "_INITVAL"), 0);
- int new_init = 0;
- for (int i = 0; i < 16; i++) {
- int old_index = 0;
- for (int k = 0; k < 4; k++) {
- if (i & (1 << k))
- old_index |= (1 << inputs.at(k).second);
- }
- if (old_init & (1 << old_index))
- new_init |= (1 << i);
- }
- ci->params[id("LUT" + std::to_string(lut) + "_INITVAL")] = Property(new_init, 16);
- };
-
- for (auto &cell : cells) {
- CellInfo *ci = cell.second.get();
- if (ci->type == id_TRELLIS_SLICE && str_or_default(ci->params, id_MODE, "LOGIC") == "LOGIC") {
- proc_lut(ci, 0);
- proc_lut(ci, 1);
- }
- }
-}
-
void Arch::setup_wire_locations()
{
wire_loc_overrides.clear();