Merge branch 'master' of gitlab.com:SymbioticEDA/nextpnr into chipdbng
This commit is contained in:
commit
4fe8ba5e9a
@ -66,39 +66,64 @@ static float random_float_upto(rnd_state &rnd, float limit)
|
|||||||
|
|
||||||
static int random_int_between(rnd_state &rnd, int a, int b)
|
static int random_int_between(rnd_state &rnd, int a, int b)
|
||||||
{
|
{
|
||||||
return a + int(random_float_upto(rnd, b - a));
|
return a + int(random_float_upto(rnd, b - a) - 0.00001);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initial random placement
|
// Initial random placement
|
||||||
static void place_initial(Design *design, CellInfo *cell, rnd_state &rnd)
|
static void place_initial(Design *design, CellInfo *cell, rnd_state &rnd)
|
||||||
{
|
{
|
||||||
BelId best_bel = BelId();
|
bool all_placed = false;
|
||||||
float best_score = std::numeric_limits<float>::infinity();
|
int iters = 25;
|
||||||
Chip &chip = design->chip;
|
while (!all_placed) {
|
||||||
if (cell->bel != BelId()) {
|
BelId best_bel = BelId();
|
||||||
chip.unbindBel(cell->bel);
|
float best_score = std::numeric_limits<float>::infinity(),
|
||||||
cell->bel = BelId();
|
best_ripup_score = std::numeric_limits<float>::infinity();
|
||||||
}
|
Chip &chip = design->chip;
|
||||||
BelType targetType = belTypeFromId(cell->type);
|
CellInfo *ripup_target = nullptr;
|
||||||
for (auto bel : chip.getBels()) {
|
BelId ripup_bel = BelId();
|
||||||
if (chip.getBelType(bel) == targetType && chip.checkBelAvail(bel) &&
|
if (cell->bel != BelId()) {
|
||||||
isValidBelForCell(design, cell, bel)) {
|
chip.unbindBel(cell->bel);
|
||||||
float score = random_float_upto(rnd, 1.0);
|
cell->bel = BelId();
|
||||||
if (score <= best_score) {
|
}
|
||||||
best_score = score;
|
BelType targetType = belTypeFromId(cell->type);
|
||||||
best_bel = bel;
|
for (auto bel : chip.getBels()) {
|
||||||
|
if (chip.getBelType(bel) == targetType &&
|
||||||
|
isValidBelForCell(design, cell, bel)) {
|
||||||
|
if (chip.checkBelAvail(bel)) {
|
||||||
|
float score = random_float_upto(rnd, 1.0);
|
||||||
|
if (score <= best_score) {
|
||||||
|
best_score = score;
|
||||||
|
best_bel = bel;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
float score = random_float_upto(rnd, 1.0);
|
||||||
|
if (score <= best_ripup_score) {
|
||||||
|
best_ripup_score = score;
|
||||||
|
ripup_target =
|
||||||
|
design->cells.at(chip.getBelCell(bel, true));
|
||||||
|
ripup_bel = bel;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
if (best_bel == BelId()) {
|
||||||
if (best_bel == BelId()) {
|
if (iters == 0 || ripup_bel == BelId())
|
||||||
log_error("failed to place cell '%s' of type '%s'\n",
|
log_error("failed to place cell '%s' of type '%s'\n",
|
||||||
cell->name.c_str(), cell->type.c_str());
|
cell->name.c_str(), cell->type.c_str());
|
||||||
}
|
--iters;
|
||||||
cell->bel = best_bel;
|
chip.unbindBel(ripup_target->bel);
|
||||||
chip.bindBel(cell->bel, cell->name);
|
ripup_target->bel = BelId();
|
||||||
|
best_bel = ripup_bel;
|
||||||
|
} else {
|
||||||
|
all_placed = true;
|
||||||
|
}
|
||||||
|
cell->bel = best_bel;
|
||||||
|
chip.bindBel(cell->bel, cell->name);
|
||||||
|
|
||||||
// Back annotate location
|
// Back annotate location
|
||||||
cell->attrs["BEL"] = chip.getBelName(cell->bel).str();
|
cell->attrs["BEL"] = chip.getBelName(cell->bel).str();
|
||||||
|
cell = ripup_target;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stores the state of the SA placer
|
// Stores the state of the SA placer
|
||||||
@ -268,7 +293,7 @@ BelId random_bel_for_cell(Design *design, CellInfo *cell, SAState &state,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void place_design_sa(Design *design)
|
void place_design_sa(Design *design, int seed)
|
||||||
{
|
{
|
||||||
SAState state;
|
SAState state;
|
||||||
|
|
||||||
@ -304,7 +329,7 @@ void place_design_sa(Design *design)
|
|||||||
}
|
}
|
||||||
log_info("place_constraints placed %d\n", int(placed_cells));
|
log_info("place_constraints placed %d\n", int(placed_cells));
|
||||||
rnd_state rnd;
|
rnd_state rnd;
|
||||||
rnd.state = 1;
|
rnd.state = seed;
|
||||||
std::vector<CellInfo *> autoplaced;
|
std::vector<CellInfo *> autoplaced;
|
||||||
// Sort to-place cells for deterministic initial placement
|
// Sort to-place cells for deterministic initial placement
|
||||||
for (auto cell : design->cells) {
|
for (auto cell : design->cells) {
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
|
|
||||||
NEXTPNR_NAMESPACE_BEGIN
|
NEXTPNR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
extern void place_design_sa(Design *design);
|
extern void place_design_sa(Design *design, int seed);
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_END
|
NEXTPNR_NAMESPACE_END
|
||||||
|
|
||||||
|
@ -440,8 +440,8 @@ void route_design(Design *design, bool verbose)
|
|||||||
"routing.\n",
|
"routing.\n",
|
||||||
int(netsQueue.size()));
|
int(netsQueue.size()));
|
||||||
|
|
||||||
ripup_pip_penalty += 5;
|
ripup_pip_penalty *= 1.5;
|
||||||
ripup_wire_penalty += 5;
|
ripup_wire_penalty *= 1.5;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,8 +24,8 @@
|
|||||||
|
|
||||||
NEXTPNR_NAMESPACE_BEGIN
|
NEXTPNR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
static const NetInfo *get_net_or_nullptr(const CellInfo *cell,
|
static const NetInfo *get_net_or_empty(const CellInfo *cell,
|
||||||
const IdString port)
|
const IdString port)
|
||||||
{
|
{
|
||||||
auto found = cell->ports.find(port);
|
auto found = cell->ports.find(port);
|
||||||
if (found != cell->ports.end())
|
if (found != cell->ports.end())
|
||||||
@ -38,46 +38,53 @@ static bool logicCellsCompatible(const std::vector<const CellInfo *> &cells)
|
|||||||
{
|
{
|
||||||
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;
|
||||||
std::unordered_set<const NetInfo *> locals;
|
static std::unordered_set<IdString> locals;
|
||||||
|
locals.clear();
|
||||||
|
|
||||||
for (auto cell : cells) {
|
for (auto cell : cells) {
|
||||||
if (bool_or_default(cell->params, "DFF_ENABLE")) {
|
if (bool_or_default(cell->params, "DFF_ENABLE")) {
|
||||||
if (!dffs_exist) {
|
if (!dffs_exist) {
|
||||||
dffs_exist = true;
|
dffs_exist = true;
|
||||||
cen = get_net_or_nullptr(cell, "CEN");
|
cen = get_net_or_empty(cell, "CEN");
|
||||||
clk = get_net_or_nullptr(cell, "CLK");
|
clk = get_net_or_empty(cell, "CLK");
|
||||||
sr = get_net_or_nullptr(cell, "SR");
|
sr = get_net_or_empty(cell, "SR");
|
||||||
|
|
||||||
if (!is_global_net(cen))
|
if (!is_global_net(cen) && cen != nullptr)
|
||||||
locals.insert(cen);
|
locals.insert(cen->name);
|
||||||
if (!is_global_net(clk))
|
if (!is_global_net(clk) && clk != nullptr)
|
||||||
locals.insert(clk);
|
locals.insert(clk->name);
|
||||||
if (!is_global_net(sr))
|
if (!is_global_net(sr) && sr != nullptr)
|
||||||
locals.insert(sr);
|
locals.insert(sr->name);
|
||||||
|
|
||||||
if (bool_or_default(cell->params, "NEG_CLK")) {
|
if (bool_or_default(cell->params, "NEG_CLK")) {
|
||||||
dffs_neg = true;
|
dffs_neg = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (cen != get_net_or_nullptr(cell, "CEN"))
|
if (cen != get_net_or_empty(cell, "CEN"))
|
||||||
return false;
|
return false;
|
||||||
if (clk != get_net_or_nullptr(cell, "CLK"))
|
if (clk != get_net_or_empty(cell, "CLK"))
|
||||||
return false;
|
return false;
|
||||||
if (sr != get_net_or_nullptr(cell, "SR"))
|
if (sr != get_net_or_empty(cell, "SR"))
|
||||||
return false;
|
return false;
|
||||||
if (dffs_neg != bool_or_default(cell->params, "NEG_CLK"))
|
if (dffs_neg != bool_or_default(cell->params, "NEG_CLK"))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
locals.insert(get_net_or_nullptr(cell, "I0"));
|
const NetInfo *i0 = get_net_or_empty(cell, "I0"),
|
||||||
locals.insert(get_net_or_nullptr(cell, "I1"));
|
*i1 = get_net_or_empty(cell, "I1"),
|
||||||
locals.insert(get_net_or_nullptr(cell, "I2"));
|
*i2 = get_net_or_empty(cell, "I2"),
|
||||||
locals.insert(get_net_or_nullptr(cell, "I3"));
|
*i3 = get_net_or_empty(cell, "I3");
|
||||||
|
if (i0 != nullptr)
|
||||||
|
locals.insert(i0->name);
|
||||||
|
if (i1 != nullptr)
|
||||||
|
locals.insert(i1->name);
|
||||||
|
if (i2 != nullptr)
|
||||||
|
locals.insert(i2->name);
|
||||||
|
if (i3 != nullptr)
|
||||||
|
locals.insert(i3->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
locals.erase(nullptr); // disconnected signals don't use local tracks
|
|
||||||
|
|
||||||
return locals.size() <= 32;
|
return locals.size() <= 32;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
*/
|
*/
|
||||||
#include "bitstream.h"
|
#include "bitstream.h"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_BEGIN
|
NEXTPNR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
@ -59,11 +60,16 @@ void set_config(const TileInfoPOD &ti,
|
|||||||
if (index == -1) {
|
if (index == -1) {
|
||||||
for (int i = 0; i < cfg.num_bits; i++) {
|
for (int i = 0; i < cfg.num_bits; i++) {
|
||||||
int8_t &cbit = tile_cfg.at(cfg.bits[i].row).at(cfg.bits[i].col);
|
int8_t &cbit = tile_cfg.at(cfg.bits[i].row).at(cfg.bits[i].col);
|
||||||
|
if (cbit && !value)
|
||||||
|
log_error("clearing already set config bit %s", name.c_str());
|
||||||
cbit = value;
|
cbit = value;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
int8_t &cbit = tile_cfg.at(cfg.bits[index].row).at(cfg.bits[index].col);
|
int8_t &cbit = tile_cfg.at(cfg.bits[index].row).at(cfg.bits[index].col);
|
||||||
cbit = value;
|
cbit = value;
|
||||||
|
if (cbit && !value)
|
||||||
|
log_error("clearing already set config bit %s[%d]", name.c_str(),
|
||||||
|
index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,7 +185,8 @@ void write_asc(const Design &design, std::ostream &out)
|
|||||||
for (int i = 0; i < 20; i++)
|
for (int i = 0; i < 20; i++)
|
||||||
set_config(ti, config.at(y).at(x), "LC_" + std::to_string(z),
|
set_config(ti, config.at(y).at(x), "LC_" + std::to_string(z),
|
||||||
lc.at(i), i);
|
lc.at(i), i);
|
||||||
set_config(ti, config.at(y).at(x), "NegClk", neg_clk);
|
if (dff_enable)
|
||||||
|
set_config(ti, config.at(y).at(x), "NegClk", neg_clk);
|
||||||
} else if (cell.second->type == "SB_IO") {
|
} else if (cell.second->type == "SB_IO") {
|
||||||
const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_IO];
|
const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_IO];
|
||||||
unsigned pin_type = get_param_or_def(cell.second, "PIN_TYPE");
|
unsigned pin_type = get_param_or_def(cell.second, "PIN_TYPE");
|
||||||
|
@ -82,6 +82,8 @@ int main(int argc, char *argv[])
|
|||||||
"PCF constraints file to ingest");
|
"PCF constraints file to ingest");
|
||||||
options.add_options()("asc", po::value<std::string>(),
|
options.add_options()("asc", po::value<std::string>(),
|
||||||
"asc bitstream file to write");
|
"asc bitstream file to write");
|
||||||
|
options.add_options()("seed", po::value<int>(),
|
||||||
|
"seed value for random number generator");
|
||||||
options.add_options()("version,V", "show version");
|
options.add_options()("version,V", "show version");
|
||||||
options.add_options()("lp384", "set device type to iCE40LP384");
|
options.add_options()("lp384", "set device type to iCE40LP384");
|
||||||
options.add_options()("lp1k", "set device type to iCE40LP1K");
|
options.add_options()("lp1k", "set device type to iCE40LP1K");
|
||||||
@ -223,8 +225,16 @@ int main(int argc, char *argv[])
|
|||||||
|
|
||||||
pack_design(&design);
|
pack_design(&design);
|
||||||
print_utilisation(&design);
|
print_utilisation(&design);
|
||||||
|
|
||||||
|
int seed = 1;
|
||||||
|
if (vm.count("seed")) {
|
||||||
|
seed = vm["seed"].as<int>();
|
||||||
|
if (seed == 0)
|
||||||
|
log_error("seed must be non-zero value");
|
||||||
|
}
|
||||||
|
|
||||||
if (!vm.count("pack-only")) {
|
if (!vm.count("pack-only")) {
|
||||||
place_design_sa(&design);
|
place_design_sa(&design, seed);
|
||||||
route_design(&design, verbose);
|
route_design(&design, verbose);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -279,7 +279,9 @@ static void pack_io(Design *design)
|
|||||||
static void insert_global(Design *design, NetInfo *net, bool is_reset,
|
static void insert_global(Design *design, NetInfo *net, bool is_reset,
|
||||||
bool is_cen)
|
bool is_cen)
|
||||||
{
|
{
|
||||||
CellInfo *gb = create_ice_cell(design, "SB_GB");
|
std::string glb_name = net->name.str() + std::string("_$glb_") +
|
||||||
|
(is_reset ? "sr" : (is_cen ? "ce" : "clk"));
|
||||||
|
CellInfo *gb = create_ice_cell(design, "SB_GB", "$gbuf_" + glb_name);
|
||||||
gb->ports["USER_SIGNAL_TO_GLOBAL_BUFFER"].net = net;
|
gb->ports["USER_SIGNAL_TO_GLOBAL_BUFFER"].net = net;
|
||||||
PortRef pr;
|
PortRef pr;
|
||||||
pr.cell = gb;
|
pr.cell = gb;
|
||||||
@ -289,8 +291,7 @@ static void insert_global(Design *design, NetInfo *net, bool is_reset,
|
|||||||
pr.cell = gb;
|
pr.cell = gb;
|
||||||
pr.port = "GLOBAL_BUFFER_OUTPUT";
|
pr.port = "GLOBAL_BUFFER_OUTPUT";
|
||||||
NetInfo *glbnet = new NetInfo();
|
NetInfo *glbnet = new NetInfo();
|
||||||
glbnet->name = net->name.str() + std::string("_glb_") +
|
glbnet->name = glb_name;
|
||||||
(is_reset ? "sr" : (is_cen ? "ce" : "clk"));
|
|
||||||
glbnet->driver = pr;
|
glbnet->driver = pr;
|
||||||
design->nets[glbnet->name] = glbnet;
|
design->nets[glbnet->name] = glbnet;
|
||||||
gb->ports["GLOBAL_BUFFER_OUTPUT"].net = glbnet;
|
gb->ports["GLOBAL_BUFFER_OUTPUT"].net = glbnet;
|
||||||
@ -363,19 +364,22 @@ static void promote_globals(Design *design)
|
|||||||
++prom_resets;
|
++prom_resets;
|
||||||
clock_count.erase(rstnet->name);
|
clock_count.erase(rstnet->name);
|
||||||
reset_count.erase(rstnet->name);
|
reset_count.erase(rstnet->name);
|
||||||
|
cen_count.erase(rstnet->name);
|
||||||
} else if (global_cen->second > global_clock->second && prom_cens < 4) {
|
} else if (global_cen->second > global_clock->second && prom_cens < 4) {
|
||||||
NetInfo *cennet = design->nets[global_cen->first];
|
NetInfo *cennet = design->nets[global_cen->first];
|
||||||
insert_global(design, cennet, false, true);
|
insert_global(design, cennet, false, true);
|
||||||
++prom_globals;
|
++prom_globals;
|
||||||
++prom_cens;
|
++prom_cens;
|
||||||
cen_count.erase(cennet->name);
|
|
||||||
clock_count.erase(cennet->name);
|
clock_count.erase(cennet->name);
|
||||||
|
reset_count.erase(cennet->name);
|
||||||
|
cen_count.erase(cennet->name);
|
||||||
} else if (global_clock->second != 0) {
|
} else if (global_clock->second != 0) {
|
||||||
NetInfo *clknet = design->nets[global_clock->first];
|
NetInfo *clknet = design->nets[global_clock->first];
|
||||||
insert_global(design, clknet, false, false);
|
insert_global(design, clknet, false, false);
|
||||||
++prom_globals;
|
++prom_globals;
|
||||||
clock_count.erase(clknet->name);
|
clock_count.erase(clknet->name);
|
||||||
|
reset_count.erase(clknet->name);
|
||||||
|
cen_count.erase(clknet->name);
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user