Add --placer option and refactor placer selection

Signed-off-by: David Shah <dave@ds0.me>
This commit is contained in:
David Shah 2019-03-24 11:10:20 +00:00
parent 52e05f4a07
commit 02ae21d8fc
11 changed files with 106 additions and 30 deletions

View File

@ -27,6 +27,7 @@
#include "pybindings.h"
#endif
#include <boost/algorithm/string/join.hpp>
#include <boost/filesystem/convenience.hpp>
#include <boost/program_options.hpp>
#include <fstream>
@ -120,6 +121,13 @@ po::options_description CommandHandler::getGeneralOptions()
general.add_options()("json", po::value<std::string>(), "JSON design file to ingest");
general.add_options()("seed", po::value<int>(), "seed value for random number generator");
general.add_options()("randomize-seed,r", "randomize seed value for random number generator");
general.add_options()(
"placer", po::value<std::string>(),
std::string("placer algorithm to use; available: " + boost::algorithm::join(Arch::availablePlacers, ", ") +
"; default: " + Arch::defaultPlacer)
.c_str());
general.add_options()("slack_redist_iter", po::value<int>(), "number of iterations between slack redistribution");
general.add_options()("cstrweight", po::value<float>(), "placer weighting for relative constraint satisfaction");
general.add_options()("starttemp", po::value<float>(), "placer SA start temperature");
@ -186,6 +194,17 @@ void CommandHandler::setupContext(Context *ctx)
settings->set("timing/allowFail", true);
}
if (vm.count("placer")) {
std::string placer = vm["placer"].as<std::string>();
if (std::find(Arch::availablePlacers.begin(), Arch::availablePlacers.end(), placer) ==
Arch::availablePlacers.end())
log_error("Placer algorithm '%s' is not supported (available options: %s)\n", placer.c_str(),
boost::algorithm::join(Arch::availablePlacers, ", ").c_str());
settings->set("placer", placer);
} else {
settings->set("placer", Arch::defaultPlacer);
}
if (vm.count("cstrweight")) {
settings->set("placer1/constraintWeight", vm["cstrweight"].as<float>());
}

View File

@ -45,19 +45,30 @@ class Settings
return defaultValue;
}
template <typename T> void set(const char *name, T value)
{
IdString id = ctx->id(name);
auto pair = ctx->settings.emplace(id, std::to_string(value));
if (!pair.second) {
ctx->settings[pair.first->first] = value;
}
}
template <typename T> void set(const char *name, T value);
private:
Context *ctx;
};
template <typename T> inline void Settings::set(const char *name, T value)
{
IdString id = ctx->id(name);
auto pair = ctx->settings.emplace(id, std::to_string(value));
if (!pair.second) {
ctx->settings[pair.first->first] = value;
}
}
template <> inline void Settings::set<std::string>(const char *name, std::string value)
{
IdString id = ctx->id(name);
auto pair = ctx->settings.emplace(id, value);
if (!pair.second) {
ctx->settings[pair.first->first] = value;
}
}
NEXTPNR_NAMESPACE_END
#endif // SETTINGS_H

View File

@ -490,3 +490,14 @@ a certain number of different clock signals allowed for a group of bels.
Returns true if a bell in the current configuration is valid, i.e. if
`isValidBelForCell()` would return true for the current mapping.
### static const std::string defaultPlacer
Name of the default placement algorithm for the architecture, if
`--placer` isn't specified on the command line.
### static const std::vector\<std::string\> availablePlacers
Name of available placer algorithms for the architecture, used
to provide help for and validate `--placer`.

View File

@ -508,21 +508,21 @@ bool Arch::getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay
bool Arch::place()
{
// HeAP is the default unless overriden or not built
#ifdef WITH_HEAP
if (bool_or_default(settings, id("sa_placer"), false)) {
#endif
if (!placer1(getCtx(), Placer1Cfg(getCtx())))
return false;
#ifdef WITH_HEAP
} else {
std::string placer = str_or_default(settings, id("placer"), defaultPlacer);
if (placer == "heap") {
PlacerHeapCfg cfg(getCtx());
cfg.criticalityExponent = 7;
cfg.ioBufTypes.insert(id_TRELLIS_IO);
if (!placer_heap(getCtx(), cfg))
return false;
} else if (placer == "sa") {
if (!placer1(getCtx(), Placer1Cfg(getCtx())))
return false;
} else {
log_error("ECP5 architecture does not support placer '%s'\n", placer.c_str());
}
#endif
permute_luts();
return true;
}
@ -986,4 +986,16 @@ WireId Arch::getBankECLK(int bank, int eclk)
return getWireByLocAndBasename(Location(0, 0), "G_BANK" + std::to_string(bank) + "ECLK" + std::to_string(eclk));
}
#ifdef WITH_HEAP
const std::string Arch::defaultPlacer = "heap";
#else
const std::string Arch::defaultPlacer = "sa";
#endif
const std::vector<std::string> Arch::availablePlacers = {"sa",
#ifdef WITH_HEAP
"heap"
#endif
};
NEXTPNR_NAMESPACE_END

View File

@ -1045,6 +1045,9 @@ struct Arch : BaseCtx
IdString id_srmode, id_mode;
mutable std::unordered_map<DelayKey, std::pair<bool, DelayInfo>> celldelay_cache;
static const std::string defaultPlacer;
static const std::vector<std::string> availablePlacers;
};
NEXTPNR_NAMESPACE_END

View File

@ -59,8 +59,6 @@ po::options_description ECP5CommandHandler::getArchOptions()
specific.add_options()("um5g-45k", "set device type to LFE5UM5G-45F");
specific.add_options()("um5g-85k", "set device type to LFE5UM5G-85F");
specific.add_options()("sa-placer", "use pure simulated annealing placer instead of HeAP analytic placer");
specific.add_options()("package", po::value<std::string>(), "select device package (defaults to CABGA381)");
specific.add_options()("speed", po::value<int>(), "select device speedgrade (6, 7 or 8)");
@ -152,10 +150,6 @@ std::unique_ptr<Context> ECP5CommandHandler::createContext()
}
}
auto ctx = std::unique_ptr<Context>(new Context(chipArgs));
if (vm.count("sa-placer"))
ctx->settings[ctx->id("sa_placer")] = "1";
return ctx;
}

View File

@ -21,6 +21,7 @@
#include "nextpnr.h"
#include "placer1.h"
#include "router1.h"
#include "util.h"
NEXTPNR_NAMESPACE_BEGIN
@ -439,7 +440,16 @@ bool Arch::getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay
// ---------------------------------------------------------------
bool Arch::place() { return placer1(getCtx(), Placer1Cfg(getCtx())); }
bool Arch::place()
{
std::string placer = str_or_default(settings, id("placer"), defaultPlacer);
// FIXME: No HeAP because it needs a list of IO buffers
if (placer == "sa") {
return placer1(getCtx(), Placer1Cfg(getCtx()));
} else {
log_error("Generic architecture does not support placer '%s'\n", placer.c_str());
}
}
bool Arch::route() { return router1(getCtx(), Router1Cfg(getCtx())); }
@ -476,4 +486,7 @@ TimingClockingInfo Arch::getPortClockingInfo(const CellInfo *cell, IdString port
bool Arch::isValidBelForCell(CellInfo *cell, BelId bel) const { return true; }
bool Arch::isBelLocationValid(BelId bel) const { return true; }
const std::string Arch::defaultPlacer = "sa";
const std::vector<std::string> Arch::availablePlacers = {"sa"};
NEXTPNR_NAMESPACE_END

View File

@ -240,6 +240,9 @@ struct Arch : BaseCtx
bool isValidBelForCell(CellInfo *cell, BelId bel) const;
bool isBelLocationValid(BelId bel) const;
static const std::string defaultPlacer;
static const std::vector<std::string> availablePlacers;
};
NEXTPNR_NAMESPACE_END

View File

@ -671,14 +671,17 @@ bool Arch::getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay
bool Arch::place()
{
if (bool_or_default(settings, id("heap_placer"), false)) {
std::string placer = str_or_default(settings, id("placer"), defaultPlacer);
if (placer == "heap") {
PlacerHeapCfg cfg(getCtx());
cfg.ioBufTypes.insert(id_SB_IO);
if (!placer_heap(getCtx(), cfg))
return false;
} else {
} else if (placer == "sa") {
if (!placer1(getCtx(), Placer1Cfg(getCtx())))
return false;
} else {
log_error("iCE40 architecture does not support placer '%s'\n", placer.c_str());
}
if (bool_or_default(settings, id("opt_timing"), false)) {
TimingOptCfg tocfg(getCtx());
@ -1205,4 +1208,12 @@ void Arch::assignCellInfo(CellInfo *cell)
}
}
const std::string Arch::defaultPlacer = "sa";
const std::vector<std::string> Arch::availablePlacers = {"sa",
#ifdef WITH_HEAP
"heap"
#endif
};
NEXTPNR_NAMESPACE_END

View File

@ -897,6 +897,9 @@ struct Arch : BaseCtx
IdString glb_net = getWireName(getBelPinWire(bel, id_GLOBAL_BUFFER_OUTPUT));
return std::stoi(std::string("") + glb_net.str(this).back());
}
static const std::string defaultPlacer;
static const std::vector<std::string> availablePlacers;
};
void ice40DelayFuzzerMain(Context *ctx);

View File

@ -69,8 +69,6 @@ po::options_description Ice40CommandHandler::getArchOptions()
specific.add_options()("promote-logic",
"enable promotion of 'logic' globals (in addition to clk/ce/sr by default)");
specific.add_options()("no-promote-globals", "disable all global promotion");
specific.add_options()("heap-placer",
"use HeAP analytic placer instead of simulated annealing (faster, experimental)");
specific.add_options()("opt-timing", "run post-placement timing optimisation pass (experimental)");
specific.add_options()("tmfuzz", "run path delay estimate fuzzer");
specific.add_options()("pcf-allow-unconstrained", "don't require PCF to constrain all IO");
@ -178,8 +176,6 @@ std::unique_ptr<Context> Ice40CommandHandler::createContext()
ctx->settings[ctx->id("opt_timing")] = "1";
if (vm.count("pcf-allow-unconstrained"))
ctx->settings[ctx->id("pcf_allow_unconstrained")] = "1";
if (vm.count("heap-placer"))
ctx->settings[ctx->id("heap_placer")] = "1";
return ctx;
}