From ecc2c486d9988a44eed7c2a197b0a0e50bd96248 Mon Sep 17 00:00:00 2001 From: David Shah Date: Tue, 19 Jun 2018 13:48:04 +0200 Subject: ice40: Fix constant packer Signed-off-by: David Shah --- ice40/pack.cc | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/ice40/pack.cc b/ice40/pack.cc index 1569fe01..542e3e96 100644 --- a/ice40/pack.cc +++ b/ice40/pack.cc @@ -202,22 +202,32 @@ static void pack_constants(Context *ctx) std::vector dead_nets; + bool gnd_used = false, vcc_used = false; + for (auto net : ctx->nets) { NetInfo *ni = net.second; if (ni->driver.cell != nullptr && ni->driver.cell->type == ctx->id("GND")) { set_net_constant(ctx, ni, gnd_net, false); - ctx->cells[gnd_cell->name] = gnd_cell; - ctx->nets[gnd_net->name] = gnd_net; + gnd_used = true; dead_nets.push_back(net.first); } else if (ni->driver.cell != nullptr && ni->driver.cell->type == ctx->id("VCC")) { set_net_constant(ctx, ni, vcc_net, true); - ctx->cells[vcc_cell->name] = vcc_cell; - ctx->nets[vcc_net->name] = vcc_net; + vcc_used = true; dead_nets.push_back(net.first); } } + if (gnd_used) { + ctx->cells[gnd_cell->name] = gnd_cell; + ctx->nets[gnd_net->name] = gnd_net; + } + + if (vcc_used) { + ctx->cells[vcc_cell->name] = vcc_cell; + ctx->nets[vcc_net->name] = vcc_net; + } + for (auto dn : dead_nets) ctx->nets.erase(dn); } -- cgit v1.2.3 From a8071a418ddb35698cf1b9958c6caddc2e839cb2 Mon Sep 17 00:00:00 2001 From: David Shah Date: Tue, 19 Jun 2018 14:10:28 +0200 Subject: ice40: Improve error reporting for invalid tristate usage Signed-off-by: David Shah --- ice40/cells.cc | 13 +++++++++---- ice40/cells.h | 3 +-- ice40/pack.cc | 23 ++++++++++++++--------- 3 files changed, 24 insertions(+), 15 deletions(-) diff --git a/ice40/cells.cc b/ice40/cells.cc index 6a8e7b5e..582e5c14 100644 --- a/ice40/cells.cc +++ b/ice40/cells.cc @@ -37,7 +37,7 @@ CellInfo *create_ice_cell(Context *ctx, IdString type, std::string name) CellInfo *new_cell = new CellInfo(); if (name.empty()) { new_cell->name = IdString(ctx, "$nextpnr_" + type.str() + "_" + - std::to_string(auto_idx++)); + std::to_string(auto_idx++)); } else { new_cell->name = ctx->id(name); } @@ -200,8 +200,8 @@ void nxio_to_sb(Context *ctx, CellInfo *nxio, CellInfo *sbio) } NetInfo *donet = sbio->ports.at(ctx->id("D_OUT_0")).net; CellInfo *tbuf = - net_driven_by(ctx, donet, [] - (const Context *ctx, const CellInfo *cell) { + net_driven_by(ctx, donet, + [](const Context *ctx, const CellInfo *cell) { return cell->type == ctx->id("$_TBUF_"); }, "Y"); @@ -210,6 +210,10 @@ void nxio_to_sb(Context *ctx, CellInfo *nxio, CellInfo *sbio) replace_port(tbuf, "A", sbio, "D_OUT_0"); replace_port(tbuf, "E", sbio, "OUTPUT_ENABLE"); ctx->nets.erase(donet->name); + if (!donet->users.empty()) + log_error("unsupported tristate IO pattern for IO buffer '%s', " + "instantiate SB_IO manually to ensure correct behaviour\n", + nxio->name.c_str(ctx)); ctx->cells.erase(tbuf->name); } } @@ -251,7 +255,8 @@ bool is_enable_port(const Context *ctx, const PortRef &port) bool is_global_net(const Context *ctx, const NetInfo *net) { - return bool(net_driven_by(ctx, net, is_gbuf, ctx->id("GLOBAL_BUFFER_OUTPUT"))); + return bool( + net_driven_by(ctx, net, is_gbuf, ctx->id("GLOBAL_BUFFER_OUTPUT"))); } NEXTPNR_NAMESPACE_END diff --git a/ice40/cells.h b/ice40/cells.h index cc1fa1cb..19568ed0 100644 --- a/ice40/cells.h +++ b/ice40/cells.h @@ -27,8 +27,7 @@ NEXTPNR_NAMESPACE_BEGIN // Create a standard iCE40 cell and return it // Name will be automatically assigned if not specified -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 inline bool is_lut(const Context *ctx, const CellInfo *cell) diff --git a/ice40/pack.cc b/ice40/pack.cc index 542e3e96..0eb6f77d 100644 --- a/ice40/pack.cc +++ b/ice40/pack.cc @@ -39,8 +39,8 @@ static void pack_lut_lutffs(Context *ctx) log_info("cell '%s' is of type '%s'\n", ci->name.c_str(ctx), ci->type.c_str(ctx)); if (is_lut(ctx, ci)) { - CellInfo *packed = - create_ice_cell(ctx, "ICESTORM_LC", ci->name.str(ctx) + "_LC"); + CellInfo *packed = create_ice_cell(ctx, "ICESTORM_LC", + ci->name.str(ctx) + "_LC"); std::copy(ci->attrs.begin(), ci->attrs.end(), std::inserter(packed->attrs, packed->attrs.begin())); packed_cells.insert(ci->name); @@ -168,7 +168,8 @@ static void set_net_constant(const Context *ctx, NetInfo *orig, for (auto user : orig->users) { if (user.cell != nullptr) { CellInfo *uc = user.cell; - log_info("%s user %s\n", orig->name.c_str(ctx), uc->name.c_str(ctx)); + log_info("%s user %s\n", orig->name.c_str(ctx), + uc->name.c_str(ctx)); if (is_lut(ctx, uc) && (user.port.str(ctx).at(0) == 'I') && !constval) { uc->ports[user.port].net = nullptr; @@ -206,7 +207,8 @@ static void pack_constants(Context *ctx) for (auto net : ctx->nets) { NetInfo *ni = net.second; - if (ni->driver.cell != nullptr && ni->driver.cell->type == ctx->id("GND")) { + if (ni->driver.cell != nullptr && + ni->driver.cell->type == ctx->id("GND")) { set_net_constant(ctx, ni, gnd_net, false); gnd_used = true; dead_nets.push_back(net.first); @@ -234,7 +236,8 @@ static void pack_constants(Context *ctx) static bool is_nextpnr_iob(Context *ctx, CellInfo *cell) { - return cell->type == ctx->id("$nextpnr_ibuf") || cell->type == ctx->id("$nextpnr_obuf") || + return cell->type == ctx->id("$nextpnr_ibuf") || + cell->type == ctx->id("$nextpnr_obuf") || cell->type == ctx->id("$nextpnr_iobuf"); } @@ -250,7 +253,8 @@ static void pack_io(Context *ctx) CellInfo *ci = cell.second; if (is_nextpnr_iob(ctx, ci)) { CellInfo *sb = nullptr; - if (ci->type == ctx->id("$nextpnr_ibuf") || ci->type == ctx->id("$nextpnr_iobuf")) { + if (ci->type == ctx->id("$nextpnr_ibuf") || + ci->type == ctx->id("$nextpnr_iobuf")) { sb = net_only_drives(ctx, ci->ports.at("O").net, is_sb_io, "PACKAGE_PIN", true, ci); @@ -262,8 +266,8 @@ static void pack_io(Context *ctx) // Trivial case, SB_IO used. Just destroy the net and the // iobuf log_info("%s feeds SB_IO %s, removing %s %s.\n", - ci->name.c_str(ctx), sb->name.c_str(ctx), ci->type.c_str(ctx), - ci->name.c_str(ctx)); + ci->name.c_str(ctx), sb->name.c_str(ctx), + ci->type.c_str(ctx), ci->name.c_str(ctx)); NetInfo *net = sb->ports.at("PACKAGE_PIN").net; if (net != nullptr) { ctx->nets.erase(net->name); @@ -271,7 +275,8 @@ static void pack_io(Context *ctx) } } else { // Create a SB_IO buffer - sb = create_ice_cell(ctx, "SB_IO"); + sb = create_ice_cell(ctx, "SB_IO", + ci->name.str(ctx) + "$sb_io"); nxio_to_sb(ctx, ci, sb); new_cells.push_back(sb); } -- cgit v1.2.3 From 786bd6b25a2d7db691e70fd2bc9a60c796e0df35 Mon Sep 17 00:00:00 2001 From: David Shah Date: Tue, 19 Jun 2018 14:31:49 +0200 Subject: place_sa: Use context-wide rng Signed-off-by: David Shah --- common/place_sa.cc | 61 +++++++++++++----------------------------------------- 1 file changed, 14 insertions(+), 47 deletions(-) diff --git a/common/place_sa.cc b/common/place_sa.cc index 7588b245..1178a247 100644 --- a/common/place_sa.cc +++ b/common/place_sa.cc @@ -42,42 +42,15 @@ NEXTPNR_NAMESPACE_BEGIN -struct rnd_state -{ - uint32_t state; -}; - -/* The state word must be initialized to non-zero */ -static uint32_t xorshift32(rnd_state &rnd) -{ - /* Algorithm "xor" from p. 4 of Marsaglia, "Xorshift RNGs" */ - uint32_t x = rnd.state; - x ^= x << 13; - x ^= x >> 17; - x ^= x << 5; - rnd.state = x; - return x; -} - -static float random_float_upto(rnd_state &rnd, float limit) -{ - return xorshift32(rnd) / (4294967296 / limit); -} - -static int random_int_between(rnd_state &rnd, int a, int b) -{ - return a + int(random_float_upto(rnd, b - a) - 0.00001); -} - // Initial random placement -static void place_initial(Context *ctx, CellInfo *cell, rnd_state &rnd) +static void place_initial(Context *ctx, CellInfo *cell) { bool all_placed = false; int iters = 25; while (!all_placed) { BelId best_bel = BelId(); - float best_score = std::numeric_limits::infinity(), - best_ripup_score = std::numeric_limits::infinity(); + uint64_t best_score = std::numeric_limits::max(), + best_ripup_score = std::numeric_limits::max(); CellInfo *ripup_target = nullptr; BelId ripup_bel = BelId(); if (cell->bel != BelId()) { @@ -89,13 +62,13 @@ static void place_initial(Context *ctx, CellInfo *cell, rnd_state &rnd) if (ctx->getBelType(bel) == targetType && isValidBelForCell(ctx, cell, bel)) { if (ctx->checkBelAvail(bel)) { - float score = random_float_upto(rnd, 1.0); + uint64_t score = ctx->rng64(); if (score <= best_score) { best_score = score; best_bel = bel; } } else { - float score = random_float_upto(rnd, 1.0); + uint64_t score = ctx->rng64(); if (score <= best_ripup_score) { best_ripup_score = score; ripup_target = @@ -173,8 +146,7 @@ static float get_wirelength(Context *ctx, NetInfo *net) } // Attempt a SA position swap, return true on success or false on failure -static bool try_swap_position(Context *ctx, CellInfo *cell, BelId newBel, - rnd_state &rnd, SAState &state) +static bool try_swap_position(Context *ctx, CellInfo *cell, BelId newBel, SAState &state) { static std::unordered_set update; static std::vector> new_lengths; @@ -232,7 +204,7 @@ static bool try_swap_position(Context *ctx, CellInfo *cell, BelId newBel, // SA acceptance criterea if (delta < 0 || (state.temp > 1e-6 && - random_float_upto(rnd, 1.0) <= std::exp(-delta / state.temp))) { + (ctx->rng() / float(0x3fffffff)) <= std::exp(-delta / state.temp))) { state.n_accept++; if (delta < 0) state.improved = true; @@ -259,17 +231,14 @@ swap_fail: // Find a random Bel of the correct type for a cell, within the specified // diameter -BelId random_bel_for_cell(Context *ctx, CellInfo *cell, SAState &state, - rnd_state &rnd) +BelId random_bel_for_cell(Context *ctx, CellInfo *cell, SAState &state) { BelType targetType = ctx->belTypeFromId(cell->type); int x = 0, y = 0; ctx->estimatePosition(cell->bel, x, y); while (true) { - int nx = random_int_between(rnd, std::max(int(x) - state.diameter, 0), - int(x) + state.diameter + 1); - int ny = random_int_between(rnd, std::max(int(y) - state.diameter, 0), - int(y) + state.diameter + 1); + int nx = ctx->rng(2 * state.diameter + 1) + std::max(x - state.diameter, 0); + int ny = ctx->rng(2 * state.diameter + 1) + std::max(y - state.diameter, 0); int beltype_idx = state.bel_types.at(targetType); if (nx >= int(state.fast_bels.at(beltype_idx).size())) continue; @@ -278,7 +247,7 @@ BelId random_bel_for_cell(Context *ctx, CellInfo *cell, SAState &state, const auto &fb = state.fast_bels.at(beltype_idx).at(nx).at(ny); if (fb.size() == 0) continue; - BelId bel = fb.at(random_int_between(rnd, 0, fb.size())); + BelId bel = fb.at(ctx->rng(int(fb.size()))); if (state.locked_bels.find(bel) != state.locked_bels.end()) continue; return bel; @@ -321,8 +290,6 @@ void place_design_sa(Context *ctx) } } log_info("place_constraints placed %d\n", int(placed_cells)); - rnd_state rnd; - rnd.state = ctx->rng(); std::vector autoplaced; // Sort to-place cells for deterministic initial placement for (auto cell : ctx->cells) { @@ -335,7 +302,7 @@ void place_design_sa(Context *ctx) [](CellInfo *a, CellInfo *b) { return a->name < b->name; }); // Place cells randomly initially for (auto cell : autoplaced) { - place_initial(ctx, cell, rnd); + place_initial(ctx, cell); placed_cells++; } // Build up a fast position/type to Bel lookup table @@ -388,11 +355,11 @@ void place_design_sa(Context *ctx) // Loop through all automatically placed cells for (auto cell : autoplaced) { // Find another random Bel for this cell - BelId try_bel = random_bel_for_cell(ctx, cell, state, rnd); + BelId try_bel = random_bel_for_cell(ctx, cell, state); // If valid, try and swap to a new position and see if // the new position is valid/worthwhile if (try_bel != BelId() && try_bel != cell->bel) - try_swap_position(ctx, cell, try_bel, rnd, state); + try_swap_position(ctx, cell, try_bel, state); } } // Heuristic to improve placement on the 8k -- cgit v1.2.3