From 031d8e811f9ce00f0c72e697789f991834d1f8f2 Mon Sep 17 00:00:00 2001 From: David Shah Date: Tue, 12 Jun 2018 13:40:22 +0200 Subject: ice40: Adding a placement validity checker Signed-off-by: David Shah --- ice40/arch_place.cc | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++++ ice40/arch_place.h | 31 +++++++++++++++++++ ice40/chip.cc | 20 ++++++++++++ ice40/chip.h | 2 ++ ice40/pack.cc | 12 ++++---- 5 files changed, 148 insertions(+), 6 deletions(-) create mode 100644 ice40/arch_place.cc create mode 100644 ice40/arch_place.h diff --git a/ice40/arch_place.cc b/ice40/arch_place.cc new file mode 100644 index 00000000..2367d981 --- /dev/null +++ b/ice40/arch_place.cc @@ -0,0 +1,89 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 Clifford Wolf + * + * 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 "arch_place.h" + +static bool logicCellsCompatible(const std::vector &cells) +{ + bool dffs_exist = false, dffs_neg = false; + const NetInfo *cen = nullptr, *clk = nullptr, *sr = nullptr; + std::unordered_set locals; + + for (auto cell : cells) { + if (std::stoi(cell->params.at("DFF_ENABLE"))) { + if (!dffs_exist) { + dffs_exist = true; + cen = cell->ports.at("CEN").net; + clk = cell->ports.at("CLK").net; + sr = cell->ports.at("SR").net; + + locals.insert(cen); + locals.insert(clk); + locals.insert(sr); + + if (std::stoi(cell->params.at("NEG_CLK"))) { + dffs_neg = true; + } + } else { + if (cen != cell->ports.at("CEN").net) + return false; + if (clk == cell->ports.at("CLK").net) + return false; + if (sr != cell->ports.at("SR").net) + return false; + if (dffs_neg != bool(std::stoi(cell->params.at("NEG_CLK")))) + return false; + } + } + + locals.insert(cell->ports.at("I0").net); + locals.insert(cell->ports.at("I1").net); + locals.insert(cell->ports.at("I2").net); + locals.insert(cell->ports.at("I3").net); + } + + locals.erase(nullptr); // disconnected signals don't use local tracks + + return locals.size() <= 32; +} + +bool isValidBelForCell(Design *design, CellInfo *cell, BelId bel) +{ + const Chip &chip = design->chip; + if (cell->type == "ICESTORM_LC") { + assert(chip.getBelType(bel) == TYPE_ICESTORM_LC); + + std::vector cells; + + for (auto bel_other : chip.getBelsAtSameTile(bel)) { + IdString cell_other = chip.getBelCell(bel_other, false); + if (cell_other != IdString()) { + const CellInfo *ci_other = design->cells[cell_other]; + cells.push_back(ci_other); + } + } + + cells.push_back(cell); + return logicCellsCompatible(cells); + + } else { + // TODO: IO cell clock checks + return true; + } +} diff --git a/ice40/arch_place.h b/ice40/arch_place.h new file mode 100644 index 00000000..19b0635f --- /dev/null +++ b/ice40/arch_place.h @@ -0,0 +1,31 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * Copyright (C) 2018 Clifford Wolf + * + * 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. + * + */ + +#ifndef ICE40_ARCH_PLACE_H +#define ICE40_ARCH_PLACE_H + +#include "nextpnr.h" +// Architecure-specific placement functions + +// Whether or not a given cell can be placed at a given Bel +// This is not intended for Bel type checks, but finer-grained constraints +// such as conflicting set/reset signals, etc +bool isValidBelForCell(Chip *chip, CellInfo *cell, BelId bel); + +#endif diff --git a/ice40/chip.cc b/ice40/chip.cc index 42252fa0..21beb648 100644 --- a/ice40/chip.cc +++ b/ice40/chip.cc @@ -151,6 +151,26 @@ BelId Chip::getBelByName(IdString name) const return ret; } +BelRange Chip::getBelsAtSameTile(BelId bel) const +{ + BelRange br; + assert(bel != BelId()); + // This requires Bels at the same tile are consecutive + int x = chip_info.bel_data[bel.index].x; + int y = chip_info.bel_data[bel.index].y; + int start = bel.index, end = bel.index; + while (start >= 0 && chip_info.bel_data[start].x == x && + chip_info.bel_data[start].y == y) + start--; + start++; + br.b.cursor = start; + while (end < chip_info.num_bels && chip_info.bel_data[end].x == x && + chip_info.bel_data[end].y == y) + end++; + br.e.cursor = end; + return br; +} + WireId Chip::getWireBelPin(BelId bel, PortPin pin) const { WireId ret; diff --git a/ice40/chip.h b/ice40/chip.h index 451be9ce..097fb286 100644 --- a/ice40/chip.h +++ b/ice40/chip.h @@ -479,6 +479,8 @@ struct Chip return range; } + BelRange getBelsAtSameTile(BelId bel) const; + BelType getBelType(BelId bel) const { assert(bel != BelId()); diff --git a/ice40/pack.cc b/ice40/pack.cc index eb783f2f..ff421c17 100644 --- a/ice40/pack.cc +++ b/ice40/pack.cc @@ -90,13 +90,12 @@ static void pack_nonlut_ffs(Design *design) } // Pack constants (simple implementation) -static void pack_constants(Design *design) { - CellInfo *gnd_cell = create_ice_cell(design, "ICESTORM_LC", - "$PACKER_GND"); +static void pack_constants(Design *design) +{ + CellInfo *gnd_cell = create_ice_cell(design, "ICESTORM_LC", "$PACKER_GND"); gnd_cell->attrs["LUT_INIT"] = "0"; - CellInfo *vcc_cell = create_ice_cell(design, "ICESTORM_LC", - "$PACKER_VCC"); + CellInfo *vcc_cell = create_ice_cell(design, "ICESTORM_LC", "$PACKER_VCC"); vcc_cell->attrs["LUT_INIT"] = "1"; for (auto net : design->nets) { @@ -105,7 +104,8 @@ static void pack_constants(Design *design) { ni->driver.cell = gnd_cell; ni->driver.port = "O"; design->cells[gnd_cell->name] = gnd_cell; - } else if (ni->driver.cell != nullptr && ni->driver.cell->type == "VCC") { + } else if (ni->driver.cell != nullptr && + ni->driver.cell->type == "VCC") { ni->driver.cell = vcc_cell; ni->driver.port = "O"; design->cells[vcc_cell->name] = vcc_cell; -- cgit v1.2.3