Add --placer option and refactor placer selection
Signed-off-by: David Shah <dave@ds0.me>
This commit is contained in:
parent
52e05f4a07
commit
02ae21d8fc
@ -27,6 +27,7 @@
|
|||||||
#include "pybindings.h"
|
#include "pybindings.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <boost/algorithm/string/join.hpp>
|
||||||
#include <boost/filesystem/convenience.hpp>
|
#include <boost/filesystem/convenience.hpp>
|
||||||
#include <boost/program_options.hpp>
|
#include <boost/program_options.hpp>
|
||||||
#include <fstream>
|
#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()("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()("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()("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()("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()("cstrweight", po::value<float>(), "placer weighting for relative constraint satisfaction");
|
||||||
general.add_options()("starttemp", po::value<float>(), "placer SA start temperature");
|
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);
|
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")) {
|
if (vm.count("cstrweight")) {
|
||||||
settings->set("placer1/constraintWeight", vm["cstrweight"].as<float>());
|
settings->set("placer1/constraintWeight", vm["cstrweight"].as<float>());
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,13 @@ class Settings
|
|||||||
return defaultValue;
|
return defaultValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T> void set(const char *name, T 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);
|
IdString id = ctx->id(name);
|
||||||
auto pair = ctx->settings.emplace(id, std::to_string(value));
|
auto pair = ctx->settings.emplace(id, std::to_string(value));
|
||||||
@ -54,9 +60,14 @@ class Settings
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
template <> inline void Settings::set<std::string>(const char *name, std::string value)
|
||||||
Context *ctx;
|
{
|
||||||
};
|
IdString id = ctx->id(name);
|
||||||
|
auto pair = ctx->settings.emplace(id, value);
|
||||||
|
if (!pair.second) {
|
||||||
|
ctx->settings[pair.first->first] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_END
|
NEXTPNR_NAMESPACE_END
|
||||||
|
|
||||||
|
@ -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
|
Returns true if a bell in the current configuration is valid, i.e. if
|
||||||
`isValidBelForCell()` would return true for the current mapping.
|
`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`.
|
30
ecp5/arch.cc
30
ecp5/arch.cc
@ -508,21 +508,21 @@ bool Arch::getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay
|
|||||||
|
|
||||||
bool Arch::place()
|
bool Arch::place()
|
||||||
{
|
{
|
||||||
// HeAP is the default unless overriden or not built
|
std::string placer = str_or_default(settings, id("placer"), defaultPlacer);
|
||||||
#ifdef WITH_HEAP
|
|
||||||
if (bool_or_default(settings, id("sa_placer"), false)) {
|
if (placer == "heap") {
|
||||||
#endif
|
|
||||||
if (!placer1(getCtx(), Placer1Cfg(getCtx())))
|
|
||||||
return false;
|
|
||||||
#ifdef WITH_HEAP
|
|
||||||
} else {
|
|
||||||
PlacerHeapCfg cfg(getCtx());
|
PlacerHeapCfg cfg(getCtx());
|
||||||
cfg.criticalityExponent = 7;
|
cfg.criticalityExponent = 7;
|
||||||
cfg.ioBufTypes.insert(id_TRELLIS_IO);
|
cfg.ioBufTypes.insert(id_TRELLIS_IO);
|
||||||
if (!placer_heap(getCtx(), cfg))
|
if (!placer_heap(getCtx(), cfg))
|
||||||
return false;
|
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();
|
permute_luts();
|
||||||
return true;
|
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));
|
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
|
NEXTPNR_NAMESPACE_END
|
||||||
|
@ -1045,6 +1045,9 @@ struct Arch : BaseCtx
|
|||||||
IdString id_srmode, id_mode;
|
IdString id_srmode, id_mode;
|
||||||
|
|
||||||
mutable std::unordered_map<DelayKey, std::pair<bool, DelayInfo>> celldelay_cache;
|
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
|
NEXTPNR_NAMESPACE_END
|
||||||
|
@ -59,8 +59,6 @@ po::options_description ECP5CommandHandler::getArchOptions()
|
|||||||
specific.add_options()("um5g-45k", "set device type to LFE5UM5G-45F");
|
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()("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()("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)");
|
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));
|
auto ctx = std::unique_ptr<Context>(new Context(chipArgs));
|
||||||
|
|
||||||
if (vm.count("sa-placer"))
|
|
||||||
ctx->settings[ctx->id("sa_placer")] = "1";
|
|
||||||
|
|
||||||
return ctx;
|
return ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#include "nextpnr.h"
|
#include "nextpnr.h"
|
||||||
#include "placer1.h"
|
#include "placer1.h"
|
||||||
#include "router1.h"
|
#include "router1.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_BEGIN
|
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())); }
|
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::isValidBelForCell(CellInfo *cell, BelId bel) const { return true; }
|
||||||
bool Arch::isBelLocationValid(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
|
NEXTPNR_NAMESPACE_END
|
||||||
|
@ -240,6 +240,9 @@ struct Arch : BaseCtx
|
|||||||
|
|
||||||
bool isValidBelForCell(CellInfo *cell, BelId bel) const;
|
bool isValidBelForCell(CellInfo *cell, BelId bel) const;
|
||||||
bool isBelLocationValid(BelId bel) const;
|
bool isBelLocationValid(BelId bel) const;
|
||||||
|
|
||||||
|
static const std::string defaultPlacer;
|
||||||
|
static const std::vector<std::string> availablePlacers;
|
||||||
};
|
};
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_END
|
NEXTPNR_NAMESPACE_END
|
||||||
|
@ -671,14 +671,17 @@ bool Arch::getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay
|
|||||||
|
|
||||||
bool Arch::place()
|
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());
|
PlacerHeapCfg cfg(getCtx());
|
||||||
cfg.ioBufTypes.insert(id_SB_IO);
|
cfg.ioBufTypes.insert(id_SB_IO);
|
||||||
if (!placer_heap(getCtx(), cfg))
|
if (!placer_heap(getCtx(), cfg))
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else if (placer == "sa") {
|
||||||
if (!placer1(getCtx(), Placer1Cfg(getCtx())))
|
if (!placer1(getCtx(), Placer1Cfg(getCtx())))
|
||||||
return false;
|
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)) {
|
if (bool_or_default(settings, id("opt_timing"), false)) {
|
||||||
TimingOptCfg tocfg(getCtx());
|
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
|
NEXTPNR_NAMESPACE_END
|
||||||
|
@ -897,6 +897,9 @@ struct Arch : BaseCtx
|
|||||||
IdString glb_net = getWireName(getBelPinWire(bel, id_GLOBAL_BUFFER_OUTPUT));
|
IdString glb_net = getWireName(getBelPinWire(bel, id_GLOBAL_BUFFER_OUTPUT));
|
||||||
return std::stoi(std::string("") + glb_net.str(this).back());
|
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);
|
void ice40DelayFuzzerMain(Context *ctx);
|
||||||
|
@ -69,8 +69,6 @@ po::options_description Ice40CommandHandler::getArchOptions()
|
|||||||
specific.add_options()("promote-logic",
|
specific.add_options()("promote-logic",
|
||||||
"enable promotion of 'logic' globals (in addition to clk/ce/sr by default)");
|
"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()("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()("opt-timing", "run post-placement timing optimisation pass (experimental)");
|
||||||
specific.add_options()("tmfuzz", "run path delay estimate fuzzer");
|
specific.add_options()("tmfuzz", "run path delay estimate fuzzer");
|
||||||
specific.add_options()("pcf-allow-unconstrained", "don't require PCF to constrain all IO");
|
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";
|
ctx->settings[ctx->id("opt_timing")] = "1";
|
||||||
if (vm.count("pcf-allow-unconstrained"))
|
if (vm.count("pcf-allow-unconstrained"))
|
||||||
ctx->settings[ctx->id("pcf_allow_unconstrained")] = "1";
|
ctx->settings[ctx->id("pcf_allow_unconstrained")] = "1";
|
||||||
if (vm.count("heap-placer"))
|
|
||||||
ctx->settings[ctx->id("heap_placer")] = "1";
|
|
||||||
return ctx;
|
return ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user