| /* |
| * nextpnr -- Next Generation Place and Route |
| * |
| * Copyright (C) 2018 David Shah <david@symbioticeda.com> |
| * |
| * 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<const CellInfo *> &cells) const |
| { |
| // TODO: allow different LSR/CLK and MUX/SRMODE settings once |
| // routing details are worked out |
| NetInfo *clk_sig = nullptr, *lsr_sig = nullptr; |
| std::string CLKMUX, LSRMUX, SRMODE; |
| bool first = true; |
| for (auto cell : cells) { |
| if (first) { |
| clk_sig = port_or_nullptr(cell, id_CLK); |
| lsr_sig = port_or_nullptr(cell, id_LSR); |
| CLKMUX = str_or_default(cell->params, id_CLKMUX, "CLK"); |
| LSRMUX = str_or_default(cell->params, id_LSRMUX, "LSR"); |
| SRMODE = str_or_default(cell->params, id_SRMODE, "CE_OVER_LSR"); |
| } else { |
| if (port_or_nullptr(cell, id_CLK) != clk_sig) |
| return false; |
| if (port_or_nullptr(cell, id_LSR) != lsr_sig) |
| return false; |
| if (str_or_default(cell->params, id_CLKMUX, "CLK") != CLKMUX) |
| return false; |
| if (str_or_default(cell->params, id_LSRMUX, "LSR") != LSRMUX) |
| return false; |
| if (str_or_default(cell->params, id_SRMODE, "CE_OVER_LSR") != SRMODE) |
| return false; |
| } |
| first = 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); |
| } |
| } |
| 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<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_other != bel) { |
| bel_cells.push_back(cell_other); |
| } |
| } |
| |
| bel_cells.push_back(cell); |
| return slicesCompatible(bel_cells); |
| } else { |
| // other checks |
| return true; |
| } |
| } |
| |
| NEXTPNR_NAMESPACE_END |