Refactor: remove PlacementValidityChecker and move methods to Arch
Signed-off-by: David Shah <davey1576@gmail.com>
This commit is contained in:
parent
1b7ed56f6f
commit
bdd54a6847
@ -36,7 +36,6 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "arch_place.h"
|
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_BEGIN
|
NEXTPNR_NAMESPACE_BEGIN
|
||||||
@ -48,7 +47,6 @@ class SAPlacer
|
|||||||
public:
|
public:
|
||||||
SAPlacer(Context *ctx, bool timing_driven) : ctx(ctx), timing_driven(timing_driven)
|
SAPlacer(Context *ctx, bool timing_driven) : ctx(ctx), timing_driven(timing_driven)
|
||||||
{
|
{
|
||||||
checker = new PlaceValidityChecker(ctx);
|
|
||||||
int num_bel_types = 0;
|
int num_bel_types = 0;
|
||||||
for (auto bel : ctx->getBels()) {
|
for (auto bel : ctx->getBels()) {
|
||||||
int x, y;
|
int x, y;
|
||||||
@ -222,7 +220,7 @@ class SAPlacer
|
|||||||
// Final post-pacement validitiy check
|
// Final post-pacement validitiy check
|
||||||
for (auto bel : ctx->getBels()) {
|
for (auto bel : ctx->getBels()) {
|
||||||
IdString cell = ctx->getBoundBelCell(bel);
|
IdString cell = ctx->getBoundBelCell(bel);
|
||||||
if (!checker->isBelLocationValid(bel)) {
|
if (!ctx->isBelLocationValid(bel)) {
|
||||||
std::string cell_text = "no cell";
|
std::string cell_text = "no cell";
|
||||||
if (cell != IdString())
|
if (cell != IdString())
|
||||||
cell_text = std::string("cell '") + cell.str(ctx) + "'";
|
cell_text = std::string("cell '") + cell.str(ctx) + "'";
|
||||||
@ -257,7 +255,7 @@ class SAPlacer
|
|||||||
}
|
}
|
||||||
BelType targetType = ctx->belTypeFromId(cell->type);
|
BelType targetType = ctx->belTypeFromId(cell->type);
|
||||||
for (auto bel : ctx->getBels()) {
|
for (auto bel : ctx->getBels()) {
|
||||||
if (ctx->getBelType(bel) == targetType && checker->isValidBelForCell(cell, bel)) {
|
if (ctx->getBelType(bel) == targetType && ctx->isValidBelForCell(cell, bel)) {
|
||||||
if (ctx->checkBelAvail(bel)) {
|
if (ctx->checkBelAvail(bel)) {
|
||||||
uint64_t score = ctx->rng64();
|
uint64_t score = ctx->rng64();
|
||||||
if (score <= best_score) {
|
if (score <= best_score) {
|
||||||
@ -376,7 +374,7 @@ class SAPlacer
|
|||||||
ctx->bindBel(oldBel, other_cell->name, STRENGTH_WEAK);
|
ctx->bindBel(oldBel, other_cell->name, STRENGTH_WEAK);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!checker->isBelLocationValid(newBel) || ((other != IdString() && !checker->isBelLocationValid(oldBel)))) {
|
if (!ctx->isBelLocationValid(newBel) || ((other != IdString() && !ctx->isBelLocationValid(oldBel)))) {
|
||||||
ctx->unbindBel(newBel);
|
ctx->unbindBel(newBel);
|
||||||
if (other != IdString())
|
if (other != IdString())
|
||||||
ctx->unbindBel(oldBel);
|
ctx->unbindBel(oldBel);
|
||||||
@ -457,7 +455,6 @@ class SAPlacer
|
|||||||
std::unordered_map<BelType, int> bel_types;
|
std::unordered_map<BelType, int> bel_types;
|
||||||
std::vector<std::vector<std::vector<std::vector<BelId>>>> fast_bels;
|
std::vector<std::vector<std::vector<std::vector<BelId>>>> fast_bels;
|
||||||
std::unordered_set<BelId> locked_bels;
|
std::unordered_set<BelId> locked_bels;
|
||||||
PlaceValidityChecker *checker;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
bool place_design_sa(Context *ctx, bool timing_driven)
|
bool place_design_sa(Context *ctx, bool timing_driven)
|
||||||
|
@ -15,8 +15,7 @@ bool check_all_nets_driven(Context *ctx)
|
|||||||
CellInfo *cell = cell_entry.second;
|
CellInfo *cell = cell_entry.second;
|
||||||
|
|
||||||
if (debug)
|
if (debug)
|
||||||
log_info(" Examining cell \'%s\', of type \'%s\'\n",
|
log_info(" Examining cell \'%s\', of type \'%s\'\n", cell->name.c_str(ctx), cell->type.c_str(ctx));
|
||||||
cell->name.c_str(ctx), cell->type.c_str(ctx));
|
|
||||||
for (auto port_entry : cell->ports) {
|
for (auto port_entry : cell->ports) {
|
||||||
PortInfo &port = port_entry.second;
|
PortInfo &port = port_entry.second;
|
||||||
|
|
||||||
@ -29,14 +28,12 @@ bool check_all_nets_driven(Context *ctx)
|
|||||||
|
|
||||||
if (port.net == NULL) {
|
if (port.net == NULL) {
|
||||||
if (debug)
|
if (debug)
|
||||||
log_warning(
|
log_warning(" Port \'%s\' in cell \'%s\' is unconnected\n", port.name.c_str(ctx),
|
||||||
" Port \'%s\' in cell \'%s\' is unconnected\n",
|
cell->name.c_str(ctx));
|
||||||
port.name.c_str(ctx), cell->name.c_str(ctx));
|
|
||||||
} else {
|
} else {
|
||||||
assert(port.net);
|
assert(port.net);
|
||||||
if (debug)
|
if (debug)
|
||||||
log_info(" Checking for a net named \'%s\'\n",
|
log_info(" Checking for a net named \'%s\'\n", port.net->name.c_str(ctx));
|
||||||
port.net->name.c_str(ctx));
|
|
||||||
assert(ctx->nets.count(port.net->name) > 0);
|
assert(ctx->nets.count(port.net->name) > 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -46,23 +43,19 @@ bool check_all_nets_driven(Context *ctx)
|
|||||||
NetInfo *net = net_entry.second;
|
NetInfo *net = net_entry.second;
|
||||||
|
|
||||||
assert(net->name == net_entry.first);
|
assert(net->name == net_entry.first);
|
||||||
if ((net->driver.cell != NULL) &&
|
if ((net->driver.cell != NULL) && (net->driver.cell->type != ctx->id("GND")) &&
|
||||||
(net->driver.cell->type != ctx->id("GND")) &&
|
|
||||||
(net->driver.cell->type != ctx->id("VCC"))) {
|
(net->driver.cell->type != ctx->id("VCC"))) {
|
||||||
|
|
||||||
if (debug)
|
if (debug)
|
||||||
log_info(" Checking for a driver cell named \'%s\'\n",
|
log_info(" Checking for a driver cell named \'%s\'\n", net->driver.cell->name.c_str(ctx));
|
||||||
net->driver.cell->name.c_str(ctx));
|
|
||||||
assert(ctx->cells.count(net->driver.cell->name) > 0);
|
assert(ctx->cells.count(net->driver.cell->name) > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto user : net->users) {
|
for (auto user : net->users) {
|
||||||
if ((user.cell != NULL) && (user.cell->type != ctx->id("GND")) &&
|
if ((user.cell != NULL) && (user.cell->type != ctx->id("GND")) && (user.cell->type != ctx->id("VCC"))) {
|
||||||
(user.cell->type != ctx->id("VCC"))) {
|
|
||||||
|
|
||||||
if (debug)
|
if (debug)
|
||||||
log_info(" Checking for a user cell named \'%s\'\n",
|
log_info(" Checking for a user cell named \'%s\'\n", user.cell->name.c_str(ctx));
|
||||||
user.cell->name.c_str(ctx));
|
|
||||||
assert(ctx->cells.count(user.cell->name) > 0);
|
assert(ctx->cells.count(user.cell->name) > 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -190,4 +190,7 @@ IdString Arch::getPortClock(const CellInfo *cell, IdString port) const { return
|
|||||||
|
|
||||||
bool Arch::isClockPort(const CellInfo *cell, IdString port) const { return false; }
|
bool Arch::isClockPort(const CellInfo *cell, IdString port) const { return false; }
|
||||||
|
|
||||||
|
bool Arch::isValidBelForCell(CellInfo *cell, BelId bel) const { return true; }
|
||||||
|
bool Arch::isBelLocationValid(BelId bel) const { return true; }
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_END
|
NEXTPNR_NAMESPACE_END
|
||||||
|
@ -150,6 +150,9 @@ struct Arch : BaseCtx
|
|||||||
bool getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, delay_t &delay) const;
|
bool getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, delay_t &delay) const;
|
||||||
IdString getPortClock(const CellInfo *cell, IdString port) const;
|
IdString getPortClock(const CellInfo *cell, IdString port) const;
|
||||||
bool isClockPort(const CellInfo *cell, IdString port) const;
|
bool isClockPort(const CellInfo *cell, IdString port) const;
|
||||||
|
|
||||||
|
bool isValidBelForCell(CellInfo *cell, BelId bel) const;
|
||||||
|
bool isBelLocationValid(BelId bel) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_END
|
NEXTPNR_NAMESPACE_END
|
||||||
|
@ -1,30 +0,0 @@
|
|||||||
/*
|
|
||||||
* nextpnr -- Next Generation Place and Route
|
|
||||||
*
|
|
||||||
* Copyright (C) 2018 Clifford Wolf <clifford@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 "arch_place.h"
|
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_BEGIN
|
|
||||||
|
|
||||||
PlaceValidityChecker::PlaceValidityChecker(Context *ctx) {}
|
|
||||||
|
|
||||||
bool PlaceValidityChecker::isValidBelForCell(CellInfo *cell, BelId bel) { return true; }
|
|
||||||
|
|
||||||
bool PlaceValidityChecker::isBelLocationValid(BelId bel) { return true; }
|
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_END
|
|
@ -1,45 +0,0 @@
|
|||||||
/*
|
|
||||||
* nextpnr -- Next Generation Place and Route
|
|
||||||
*
|
|
||||||
* Copyright (C) 2018 Clifford Wolf <clifford@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.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef DUMMY_ARCH_PLACE_H
|
|
||||||
#define DUMMY_ARCH_PLACE_H
|
|
||||||
|
|
||||||
#include "nextpnr.h"
|
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_BEGIN
|
|
||||||
|
|
||||||
// Architecure-specific placement functions
|
|
||||||
|
|
||||||
class PlaceValidityChecker
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
PlaceValidityChecker(Context *ctx);
|
|
||||||
|
|
||||||
// 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(CellInfo *cell, BelId bel);
|
|
||||||
|
|
||||||
// Return true whether all Bels at a given location are valid
|
|
||||||
bool isBelLocationValid(BelId bel);
|
|
||||||
};
|
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_END
|
|
||||||
|
|
||||||
#endif
|
|
@ -75,7 +75,8 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (vm.count("help") || argc == 1) {
|
if (vm.count("help") || argc == 1) {
|
||||||
std::cout << boost::filesystem::basename(argv[0]) << " -- Next Generation Place and Route (git "
|
std::cout << boost::filesystem::basename(argv[0])
|
||||||
|
<< " -- Next Generation Place and Route (git "
|
||||||
"sha1 " GIT_COMMIT_HASH_STR ")\n";
|
"sha1 " GIT_COMMIT_HASH_STR ")\n";
|
||||||
std::cout << "\n";
|
std::cout << "\n";
|
||||||
std::cout << options << "\n";
|
std::cout << options << "\n";
|
||||||
@ -83,7 +84,8 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (vm.count("version")) {
|
if (vm.count("version")) {
|
||||||
std::cout << boost::filesystem::basename(argv[0]) << " -- Next Generation Place and Route (git "
|
std::cout << boost::filesystem::basename(argv[0])
|
||||||
|
<< " -- Next Generation Place and Route (git "
|
||||||
"sha1 " GIT_COMMIT_HASH_STR ")\n";
|
"sha1 " GIT_COMMIT_HASH_STR ")\n";
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -163,6 +163,18 @@ Arch::Arch(ArchArgs args) : args(args)
|
|||||||
|
|
||||||
// Initialise regularly used IDStrings for performance
|
// Initialise regularly used IDStrings for performance
|
||||||
id_glb_buf_out = id("GLOBAL_BUFFER_OUTPUT");
|
id_glb_buf_out = id("GLOBAL_BUFFER_OUTPUT");
|
||||||
|
id_icestorm_lc = id("ICESTORM_LC");
|
||||||
|
id_sb_io = id("SB_IO");
|
||||||
|
id_sb_gb = id("SB_GB");
|
||||||
|
id_cen = id("CEN");
|
||||||
|
id_clk = id("CLK");
|
||||||
|
id_sr = id("SR");
|
||||||
|
id_i0 = id("I0");
|
||||||
|
id_i1 = id("I1");
|
||||||
|
id_i2 = id("I2");
|
||||||
|
id_i3 = id("I3");
|
||||||
|
id_dff_en = id("DFF_ENABLE");
|
||||||
|
id_neg_clk = id("NEG_CLK");
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
// -----------------------------------------------------------------------
|
||||||
|
19
ice40/arch.h
19
ice40/arch.h
@ -815,7 +815,26 @@ struct Arch : BaseCtx
|
|||||||
// Return true if a port is a net
|
// Return true if a port is a net
|
||||||
bool isGlobalNet(const NetInfo *net) const;
|
bool isGlobalNet(const NetInfo *net) const;
|
||||||
|
|
||||||
|
// -------------------------------------------------
|
||||||
|
|
||||||
|
// Perform placement validity checks, returning false on failure (all implemented in arch_place.cc)
|
||||||
|
|
||||||
|
// 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(CellInfo *cell, BelId bel) const;
|
||||||
|
|
||||||
|
// Return true whether all Bels at a given location are valid
|
||||||
|
bool isBelLocationValid(BelId bel) const;
|
||||||
|
|
||||||
|
// Helper function for above
|
||||||
|
bool logicCellsCompatible(const std::vector<const CellInfo *> &cells) const;
|
||||||
|
|
||||||
IdString id_glb_buf_out;
|
IdString id_glb_buf_out;
|
||||||
|
IdString id_icestorm_lc, id_sb_io, id_sb_gb;
|
||||||
|
IdString id_cen, id_clk, id_sr;
|
||||||
|
IdString id_i0, id_i1, id_i2, id_i3;
|
||||||
|
IdString id_dff_en, id_neg_clk;
|
||||||
};
|
};
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_END
|
NEXTPNR_NAMESPACE_END
|
||||||
|
@ -18,19 +18,12 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "arch_place.h"
|
|
||||||
#include "cells.h"
|
#include "cells.h"
|
||||||
|
#include "nextpnr.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_BEGIN
|
NEXTPNR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
PlaceValidityChecker::PlaceValidityChecker(Context *ctx)
|
|
||||||
: ctx(ctx), id_icestorm_lc(ctx, "ICESTORM_LC"), id_sb_io(ctx, "SB_IO"), id_sb_gb(ctx, "SB_GB"),
|
|
||||||
id_cen(ctx, "CEN"), id_clk(ctx, "CLK"), id_sr(ctx, "SR"), id_i0(ctx, "I0"), id_i1(ctx, "I1"),
|
|
||||||
id_i2(ctx, "I2"), id_i3(ctx, "I3"), id_dff_en(ctx, "DFF_ENABLE"), id_neg_clk(ctx, "NEG_CLK")
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static const NetInfo *get_net_or_empty(const CellInfo *cell, const IdString port)
|
static const NetInfo *get_net_or_empty(const CellInfo *cell, const IdString port)
|
||||||
{
|
{
|
||||||
auto found = cell->ports.find(port);
|
auto found = cell->ports.find(port);
|
||||||
@ -40,7 +33,7 @@ static const NetInfo *get_net_or_empty(const CellInfo *cell, const IdString port
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool PlaceValidityChecker::logicCellsCompatible(const Context *ctx, const std::vector<const CellInfo *> &cells)
|
bool Arch::logicCellsCompatible(const std::vector<const CellInfo *> &cells) const
|
||||||
{
|
{
|
||||||
bool dffs_exist = false, dffs_neg = false;
|
bool dffs_exist = false, dffs_neg = false;
|
||||||
const NetInfo *cen = nullptr, *clk = nullptr, *sr = nullptr;
|
const NetInfo *cen = nullptr, *clk = nullptr, *sr = nullptr;
|
||||||
@ -54,11 +47,11 @@ bool PlaceValidityChecker::logicCellsCompatible(const Context *ctx, const std::v
|
|||||||
clk = get_net_or_empty(cell, id_clk);
|
clk = get_net_or_empty(cell, id_clk);
|
||||||
sr = get_net_or_empty(cell, id_sr);
|
sr = get_net_or_empty(cell, id_sr);
|
||||||
|
|
||||||
if (!ctx->isGlobalNet(cen) && cen != nullptr)
|
if (!isGlobalNet(cen) && cen != nullptr)
|
||||||
locals_count++;
|
locals_count++;
|
||||||
if (!ctx->isGlobalNet(clk) && clk != nullptr)
|
if (!isGlobalNet(clk) && clk != nullptr)
|
||||||
locals_count++;
|
locals_count++;
|
||||||
if (!ctx->isGlobalNet(sr) && sr != nullptr)
|
if (!isGlobalNet(sr) && sr != nullptr)
|
||||||
locals_count++;
|
locals_count++;
|
||||||
|
|
||||||
if (bool_or_default(cell->params, id_neg_clk)) {
|
if (bool_or_default(cell->params, id_neg_clk)) {
|
||||||
@ -91,57 +84,57 @@ bool PlaceValidityChecker::logicCellsCompatible(const Context *ctx, const std::v
|
|||||||
return locals_count <= 32;
|
return locals_count <= 32;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PlaceValidityChecker::isBelLocationValid(BelId bel)
|
bool Arch::isBelLocationValid(BelId bel) const
|
||||||
{
|
{
|
||||||
if (ctx->getBelType(bel) == TYPE_ICESTORM_LC) {
|
if (getBelType(bel) == TYPE_ICESTORM_LC) {
|
||||||
std::vector<const CellInfo *> cells;
|
std::vector<const CellInfo *> bel_cells;
|
||||||
for (auto bel_other : ctx->getBelsAtSameTile(bel)) {
|
for (auto bel_other : getBelsAtSameTile(bel)) {
|
||||||
IdString cell_other = ctx->getBoundBelCell(bel_other);
|
IdString cell_other = getBoundBelCell(bel_other);
|
||||||
if (cell_other != IdString()) {
|
if (cell_other != IdString()) {
|
||||||
const CellInfo *ci_other = ctx->cells[cell_other];
|
const CellInfo *ci_other = cells.at(cell_other);
|
||||||
cells.push_back(ci_other);
|
bel_cells.push_back(ci_other);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return logicCellsCompatible(ctx, cells);
|
return logicCellsCompatible(bel_cells);
|
||||||
} else {
|
} else {
|
||||||
IdString cellId = ctx->getBoundBelCell(bel);
|
IdString cellId = getBoundBelCell(bel);
|
||||||
if (cellId == IdString())
|
if (cellId == IdString())
|
||||||
return true;
|
return true;
|
||||||
else
|
else
|
||||||
return isValidBelForCell(ctx->cells.at(cellId), bel);
|
return isValidBelForCell(cells.at(cellId), bel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PlaceValidityChecker::isValidBelForCell(CellInfo *cell, BelId bel)
|
bool Arch::isValidBelForCell(CellInfo *cell, BelId bel) const
|
||||||
{
|
{
|
||||||
if (cell->type == id_icestorm_lc) {
|
if (cell->type == id_icestorm_lc) {
|
||||||
assert(ctx->getBelType(bel) == TYPE_ICESTORM_LC);
|
assert(getBelType(bel) == TYPE_ICESTORM_LC);
|
||||||
|
|
||||||
std::vector<const CellInfo *> cells;
|
std::vector<const CellInfo *> bel_cells;
|
||||||
|
|
||||||
for (auto bel_other : ctx->getBelsAtSameTile(bel)) {
|
for (auto bel_other : getBelsAtSameTile(bel)) {
|
||||||
IdString cell_other = ctx->getBoundBelCell(bel_other);
|
IdString cell_other = getBoundBelCell(bel_other);
|
||||||
if (cell_other != IdString()) {
|
if (cell_other != IdString() && bel_other != bel) {
|
||||||
const CellInfo *ci_other = ctx->cells[cell_other];
|
const CellInfo *ci_other = cells.at(cell_other);
|
||||||
cells.push_back(ci_other);
|
bel_cells.push_back(ci_other);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cells.push_back(cell);
|
bel_cells.push_back(cell);
|
||||||
return logicCellsCompatible(ctx, cells);
|
return logicCellsCompatible(bel_cells);
|
||||||
} else if (cell->type == id_sb_io) {
|
} else if (cell->type == id_sb_io) {
|
||||||
return ctx->getBelPackagePin(bel) != "";
|
return getBelPackagePin(bel) != "";
|
||||||
} else if (cell->type == id_sb_gb) {
|
} else if (cell->type == id_sb_gb) {
|
||||||
bool is_reset = false, is_cen = false;
|
bool is_reset = false, is_cen = false;
|
||||||
assert(cell->ports.at(ctx->id("GLOBAL_BUFFER_OUTPUT")).net != nullptr);
|
assert(cell->ports.at(id_glb_buf_out).net != nullptr);
|
||||||
for (auto user : cell->ports.at(ctx->id("GLOBAL_BUFFER_OUTPUT")).net->users) {
|
for (auto user : cell->ports.at(id_glb_buf_out).net->users) {
|
||||||
if (is_reset_port(ctx, user))
|
if (is_reset_port(this, user))
|
||||||
is_reset = true;
|
is_reset = true;
|
||||||
if (is_enable_port(ctx, user))
|
if (is_enable_port(this, user))
|
||||||
is_cen = true;
|
is_cen = true;
|
||||||
}
|
}
|
||||||
IdString glb_net = ctx->getWireName(ctx->getWireBelPin(bel, PIN_GLOBAL_BUFFER_OUTPUT));
|
IdString glb_net = getWireName(getWireBelPin(bel, PIN_GLOBAL_BUFFER_OUTPUT));
|
||||||
int glb_id = std::stoi(std::string("") + glb_net.str(ctx).back());
|
int glb_id = std::stoi(std::string("") + glb_net.str(this).back());
|
||||||
if (is_reset && is_cen)
|
if (is_reset && is_cen)
|
||||||
return false;
|
return false;
|
||||||
else if (is_reset)
|
else if (is_reset)
|
||||||
|
@ -1,52 +0,0 @@
|
|||||||
/*
|
|
||||||
* nextpnr -- Next Generation Place and Route
|
|
||||||
*
|
|
||||||
* Copyright (C) 2018 Clifford Wolf <clifford@symbioticeda.com>
|
|
||||||
* 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, NeEGLIGENCE 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
|
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_BEGIN
|
|
||||||
|
|
||||||
class PlaceValidityChecker
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
PlaceValidityChecker(Context *ctx);
|
|
||||||
// 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(CellInfo *cell, BelId bel);
|
|
||||||
|
|
||||||
// Return true whether all Bels at a given location are valid
|
|
||||||
bool isBelLocationValid(BelId bel);
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool logicCellsCompatible(const Context *ctx, const std::vector<const CellInfo *> &cells);
|
|
||||||
Context *ctx;
|
|
||||||
IdString id_icestorm_lc, id_sb_io, id_sb_gb;
|
|
||||||
IdString id_cen, id_clk, id_sr;
|
|
||||||
IdString id_i0, id_i1, id_i2, id_i3;
|
|
||||||
IdString id_dff_en, id_neg_clk;
|
|
||||||
};
|
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_END
|
|
||||||
|
|
||||||
#endif
|
|
@ -227,7 +227,7 @@ void nxio_to_sb(Context *ctx, CellInfo *nxio, CellInfo *sbio)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_clock_port(const Context *ctx, const PortRef &port)
|
bool is_clock_port(const BaseCtx *ctx, const PortRef &port)
|
||||||
{
|
{
|
||||||
if (port.cell == nullptr)
|
if (port.cell == nullptr)
|
||||||
return false;
|
return false;
|
||||||
@ -240,7 +240,7 @@ bool is_clock_port(const Context *ctx, const PortRef &port)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_reset_port(const Context *ctx, const PortRef &port)
|
bool is_reset_port(const BaseCtx *ctx, const PortRef &port)
|
||||||
{
|
{
|
||||||
if (port.cell == nullptr)
|
if (port.cell == nullptr)
|
||||||
return false;
|
return false;
|
||||||
@ -251,7 +251,7 @@ bool is_reset_port(const Context *ctx, const PortRef &port)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_enable_port(const Context *ctx, const PortRef &port)
|
bool is_enable_port(const BaseCtx *ctx, const PortRef &port)
|
||||||
{
|
{
|
||||||
if (port.cell == nullptr)
|
if (port.cell == nullptr)
|
||||||
return false;
|
return false;
|
||||||
|
@ -30,10 +30,10 @@ NEXTPNR_NAMESPACE_BEGIN
|
|||||||
CellInfo *create_ice_cell(Context *ctx, IdString type, std::string name = "");
|
CellInfo *create_ice_cell(Context *ctx, IdString type, std::string name = "");
|
||||||
|
|
||||||
// Return true if a cell is a LUT
|
// Return true if a cell is a LUT
|
||||||
inline bool is_lut(const Context *ctx, const CellInfo *cell) { return cell->type == ctx->id("SB_LUT4"); }
|
inline bool is_lut(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("SB_LUT4"); }
|
||||||
|
|
||||||
// Return true if a cell is a flipflop
|
// Return true if a cell is a flipflop
|
||||||
inline bool is_ff(const Context *ctx, const CellInfo *cell)
|
inline bool is_ff(const BaseCtx *ctx, const CellInfo *cell)
|
||||||
{
|
{
|
||||||
return cell->type == ctx->id("SB_DFF") || cell->type == ctx->id("SB_DFFE") || cell->type == ctx->id("SB_DFFSR") ||
|
return cell->type == ctx->id("SB_DFF") || cell->type == ctx->id("SB_DFFE") || cell->type == ctx->id("SB_DFFSR") ||
|
||||||
cell->type == ctx->id("SB_DFFR") || cell->type == ctx->id("SB_DFFSS") || cell->type == ctx->id("SB_DFFS") ||
|
cell->type == ctx->id("SB_DFFR") || cell->type == ctx->id("SB_DFFSS") || cell->type == ctx->id("SB_DFFS") ||
|
||||||
@ -46,26 +46,26 @@ inline bool is_ff(const Context *ctx, const CellInfo *cell)
|
|||||||
cell->type == ctx->id("SB_DFFNESS") || cell->type == ctx->id("SB_DFFNES");
|
cell->type == ctx->id("SB_DFFNESS") || cell->type == ctx->id("SB_DFFNES");
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool is_carry(const Context *ctx, const CellInfo *cell) { return cell->type == ctx->id("SB_CARRY"); }
|
inline bool is_carry(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("SB_CARRY"); }
|
||||||
|
|
||||||
inline bool is_lc(const Context *ctx, const CellInfo *cell) { return cell->type == ctx->id("ICESTORM_LC"); }
|
inline bool is_lc(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("ICESTORM_LC"); }
|
||||||
|
|
||||||
// Return true if a cell is a SB_IO
|
// Return true if a cell is a SB_IO
|
||||||
inline bool is_sb_io(const Context *ctx, const CellInfo *cell) { return cell->type == ctx->id("SB_IO"); }
|
inline bool is_sb_io(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("SB_IO"); }
|
||||||
|
|
||||||
// Return true if a cell is a global buffer
|
// Return true if a cell is a global buffer
|
||||||
inline bool is_gbuf(const Context *ctx, const CellInfo *cell) { return cell->type == ctx->id("SB_GB"); }
|
inline bool is_gbuf(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("SB_GB"); }
|
||||||
|
|
||||||
// Return true if a cell is a RAM
|
// Return true if a cell is a RAM
|
||||||
inline bool is_ram(const Context *ctx, const CellInfo *cell)
|
inline bool is_ram(const BaseCtx *ctx, const CellInfo *cell)
|
||||||
{
|
{
|
||||||
return cell->type == ctx->id("SB_RAM40_4K") || cell->type == ctx->id("SB_RAM40_4KNR") ||
|
return cell->type == ctx->id("SB_RAM40_4K") || cell->type == ctx->id("SB_RAM40_4KNR") ||
|
||||||
cell->type == ctx->id("SB_RAM40_4KNW") || cell->type == ctx->id("SB_RAM40_4KNRNW");
|
cell->type == ctx->id("SB_RAM40_4KNW") || cell->type == ctx->id("SB_RAM40_4KNRNW");
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool is_sb_lfosc(const Context *ctx, const CellInfo *cell) { return cell->type == ctx->id("SB_LFOSC"); }
|
inline bool is_sb_lfosc(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("SB_LFOSC"); }
|
||||||
|
|
||||||
inline bool is_sb_hfosc(const Context *ctx, const CellInfo *cell) { return cell->type == ctx->id("SB_HFOSC"); }
|
inline bool is_sb_hfosc(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == ctx->id("SB_HFOSC"); }
|
||||||
|
|
||||||
// Convert a SB_LUT primitive to (part of) an ICESTORM_LC, swapping ports
|
// Convert a SB_LUT primitive to (part of) an ICESTORM_LC, swapping ports
|
||||||
// as needed. Set no_dff if a DFF is not being used, so that the output
|
// as needed. Set no_dff if a DFF is not being used, so that the output
|
||||||
@ -82,13 +82,13 @@ void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_l
|
|||||||
void nxio_to_sb(Context *ctx, CellInfo *nxio, CellInfo *sbio);
|
void nxio_to_sb(Context *ctx, CellInfo *nxio, CellInfo *sbio);
|
||||||
|
|
||||||
// Return true if a port is a clock port
|
// Return true if a port is a clock port
|
||||||
bool is_clock_port(const Context *ctx, const PortRef &port);
|
bool is_clock_port(const BaseCtx *ctx, const PortRef &port);
|
||||||
|
|
||||||
// Return true if a port is a reset port
|
// Return true if a port is a reset port
|
||||||
bool is_reset_port(const Context *ctx, const PortRef &port);
|
bool is_reset_port(const BaseCtx *ctx, const PortRef &port);
|
||||||
|
|
||||||
// Return true if a port is a clock enable port
|
// Return true if a port is a clock enable port
|
||||||
bool is_enable_port(const Context *ctx, const PortRef &port);
|
bool is_enable_port(const BaseCtx *ctx, const PortRef &port);
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_END
|
NEXTPNR_NAMESPACE_END
|
||||||
|
|
||||||
|
@ -125,7 +125,8 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
if (vm.count("help") || argc == 1) {
|
if (vm.count("help") || argc == 1) {
|
||||||
help:
|
help:
|
||||||
std::cout << boost::filesystem::basename(argv[0]) << " -- Next Generation Place and Route (git "
|
std::cout << boost::filesystem::basename(argv[0])
|
||||||
|
<< " -- Next Generation Place and Route (git "
|
||||||
"sha1 " GIT_COMMIT_HASH_STR ")\n";
|
"sha1 " GIT_COMMIT_HASH_STR ")\n";
|
||||||
std::cout << "\n";
|
std::cout << "\n";
|
||||||
std::cout << options << "\n";
|
std::cout << options << "\n";
|
||||||
@ -133,7 +134,8 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (vm.count("version")) {
|
if (vm.count("version")) {
|
||||||
std::cout << boost::filesystem::basename(argv[0]) << " -- Next Generation Place and Route (git "
|
std::cout << boost::filesystem::basename(argv[0])
|
||||||
|
<< " -- Next Generation Place and Route (git "
|
||||||
"sha1 " GIT_COMMIT_HASH_STR ")\n";
|
"sha1 " GIT_COMMIT_HASH_STR ")\n";
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user