From efb58711b0dfcdb8080f63bd64d3f9d9fafd2637 Mon Sep 17 00:00:00 2001 From: gatecat Date: Thu, 31 Mar 2022 11:17:57 +0100 Subject: ecp5: Split the SLICE bel into separate LUT/FF/RAMW bels --- ecp5/arch_place.cc | 237 +++++++++++++++++++++++++++++++---------------------- 1 file changed, 138 insertions(+), 99 deletions(-) (limited to 'ecp5/arch_place.cc') 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 &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 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 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> inputs; - std::vector 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(); -- cgit v1.2.3