/* * nextpnr -- Next Generation Place and Route * * Copyright (C) 2018 David Shah * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * */ #include "cells.h" #include "log.h" #include "nextpnr.h" #include "util.h" NEXTPNR_NAMESPACE_BEGIN inline NetInfo *port_or_nullptr(const CellInfo *cell, IdString name) { auto found = cell->ports.find(name); if (found == cell->ports.end()) return nullptr; return found->second.net; } bool Arch::slicesCompatible(const std::vector &cells) 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) return false; if (cell->sliceInfo.lsrmux != LSRMUX) return false; if (cell->sliceInfo.srmode != SRMODE) return false; } first = 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 slicesCompatible(bel_cells); } else { CellInfo *cell = getBoundBelCell(bel); if (cell == nullptr) return true; else return isValidBelForCell(cell, bel); } } bool Arch::isValidBelForCell(CellInfo *cell, BelId bel) const { if (cell->type == id_TRELLIS_SLICE) { NPNR_ASSERT(getBelType(bel) == id_TRELLIS_SLICE); std::vector bel_cells; Loc bel_loc = getBelLocation(bel); if (cell->sliceInfo.has_l6mux && ((bel_loc.z % 2) == 1)) return false; for (auto bel_other : getBelsByTile(bel_loc.x, bel_loc.y)) { CellInfo *cell_other = getBoundBelCell(bel_other); if (cell_other != nullptr && bel_other != bel) { bel_cells.push_back(cell_other); } } bel_cells.push_back(cell); return slicesCompatible(bel_cells); } else if (cell->type == id_DCUA || cell->type == id_EXTREFB || cell->type == id_PCSCLKDIV) { return args.type != ArchArgs::LFE5U_25F && args.type != ArchArgs::LFE5U_45F && args.type != ArchArgs::LFE5U_85F; } else { // other checks return true; } } NEXTPNR_NAMESPACE_END