diff --git a/common/nextpnr.cc b/common/nextpnr.cc index d29d3fec..188906e2 100644 --- a/common/nextpnr.cc +++ b/common/nextpnr.cc @@ -97,20 +97,12 @@ uint32_t Context::checksum() const for (auto &w : ni.wires) { uint32_t wire_x = 123456789; wire_x = xorshift32(wire_x + xorshift32(getWireChecksum(w.first))); - wire_x = xorshift32(wire_x + xorshift32(getPipChecksum(w.second))); + wire_x = xorshift32(wire_x + xorshift32(getPipChecksum(w.second.pip))); + wire_x = xorshift32(wire_x + xorshift32(int(w.second.strength))); wire_x_sum += wire_x; } x = xorshift32(x + xorshift32(wire_x_sum)); - uint32_t pip_x_sum = 0; - for (auto &p : ni.pips) { - uint32_t pip_x = 123456789; - pip_x = xorshift32(pip_x + xorshift32(getPipChecksum(p.first))); - pip_x = xorshift32(pip_x + xorshift32(p.second)); - pip_x_sum += pip_x; - } - x = xorshift32(x + xorshift32(pip_x_sum)); - cksum_nets_sum += x; } cksum = xorshift32(cksum + xorshift32(cksum_nets_sum)); @@ -175,4 +167,32 @@ uint32_t Context::checksum() const return cksum; } +void Context::check() const +{ + for (auto &n : nets) { + auto ni = n.second; + assert(n.first == ni->name); + for (auto &w : ni->wires) { + assert(n.first == getBoundWireNet(w.first)); + if (w.second.pip != PipId()) { + assert(w.first == getPipDstWire(w.second.pip)); + assert(n.first == getBoundPipNet(w.second.pip)); + } + } + } + + for (auto w : getWires()) { + IdString net = getBoundWireNet(w); + if (net != IdString()) { + assert(nets.at(net)->wires.count(w)); + } + } + + for (auto &c : cells) { + assert(c.first == c.second->name); + if (c.second->bel != BelId()) + assert(getBoundBelCell(c.second->bel) == c.first); + } +} + NEXTPNR_NAMESPACE_END diff --git a/common/nextpnr.h b/common/nextpnr.h index 9c6c9d68..8cbead7d 100644 --- a/common/nextpnr.h +++ b/common/nextpnr.h @@ -211,6 +211,12 @@ struct PortRef delay_t budget = 0; }; +struct PipMap +{ + PipId pip = PipId(); + PlaceStrength strength = STRENGTH_NONE; +}; + struct NetInfo { IdString name; @@ -219,9 +225,7 @@ struct NetInfo std::unordered_map attrs; // wire -> uphill_pip - std::unordered_map wires; - - std::unordered_map pips; + std::unordered_map wires; }; enum PortType @@ -357,6 +361,7 @@ struct Context : Arch } uint32_t checksum() const; + void check() const; }; NEXTPNR_NAMESPACE_END diff --git a/common/place_sa.cc b/common/place_sa.cc index 6743e0ce..f4fb5aff 100644 --- a/common/place_sa.cc +++ b/common/place_sa.cc @@ -103,9 +103,7 @@ class SAPlacer cell->name.c_str(ctx), cell->type.c_str(ctx)); } - cell->bel = bel; - cell->belStrength = STRENGTH_USER; - ctx->bindBel(bel, cell->name); + ctx->bindBel(bel, cell->name, STRENGTH_USER); locked_bels.insert(bel); placed_cells++; } @@ -231,7 +229,7 @@ class SAPlacer } // Final post-pacement validitiy check for (auto bel : ctx->getBels()) { - IdString cell = ctx->getBelCell(bel, false); + IdString cell = ctx->getBoundBelCell(bel); if (!checker->isBelLocationValid(bel)) { std::string cell_text = "no cell"; if (cell != IdString()) @@ -266,7 +264,6 @@ class SAPlacer BelId ripup_bel = BelId(); if (cell->bel != BelId()) { ctx->unbindBel(cell->bel); - cell->bel = BelId(); } BelType targetType = ctx->belTypeFromId(cell->type); for (auto bel : ctx->getBels()) { @@ -283,7 +280,7 @@ class SAPlacer if (score <= best_ripup_score) { best_ripup_score = score; ripup_target = - ctx->cells.at(ctx->getBelCell(bel, true)); + ctx->cells.at(ctx->getBoundBelCell(bel)); ripup_bel = bel; } } @@ -295,14 +292,11 @@ class SAPlacer cell->name.c_str(ctx), cell->type.c_str(ctx)); --iters; ctx->unbindBel(ripup_target->bel); - ripup_target->bel = BelId(); best_bel = ripup_bel; } else { all_placed = true; } - cell->bel = best_bel; - cell->belStrength = STRENGTH_WEAK; - ctx->bindBel(cell->bel, cell->name); + ctx->bindBel(best_bel, cell->name, STRENGTH_WEAK); // Back annotate location cell->attrs[ctx->id("BEL")] = ctx->getBelName(cell->bel).str(ctx); @@ -375,7 +369,7 @@ class SAPlacer new_lengths.clear(); update.clear(); BelId oldBel = cell->bel; - IdString other = ctx->getBelCell(newBel, true); + IdString other = ctx->getBoundBelCell(newBel); CellInfo *other_cell = nullptr; wirelen_t new_wirelength = 0, delta; ctx->unbindBel(oldBel); @@ -394,10 +388,10 @@ class SAPlacer update.insert(port.second.net); } - ctx->bindBel(newBel, cell->name); + ctx->bindBel(newBel, cell->name, STRENGTH_WEAK); if (other != IdString()) { - ctx->bindBel(oldBel, other_cell->name); + ctx->bindBel(oldBel, other_cell->name, STRENGTH_WEAK); } if (!checker->isBelLocationValid(newBel) || @@ -408,10 +402,6 @@ class SAPlacer goto swap_fail; } - cell->bel = newBel; - if (other != IdString()) - other_cell->bel = oldBel; - new_wirelength = curr_wirelength; // Recalculate wirelengths for all nets touched by the peturbation @@ -442,11 +432,9 @@ class SAPlacer return true; swap_fail: - ctx->bindBel(oldBel, cell->name); - cell->bel = oldBel; + ctx->bindBel(oldBel, cell->name, STRENGTH_WEAK); if (other != IdString()) { - ctx->bindBel(newBel, other); - other_cell->bel = newBel; + ctx->bindBel(newBel, other, STRENGTH_WEAK); } return false; } @@ -498,8 +486,14 @@ bool place_design_sa(Context *ctx, bool timing_driven) SAPlacer placer(ctx, timing_driven); placer.place(); log_info("Checksum: 0x%08x\n", ctx->checksum()); +#ifndef NDEBUG + ctx->check(); +#endif return true; } catch (log_execution_error_exception) { +#ifndef NDEBUG + ctx->check(); +#endif return false; } } diff --git a/common/route.cc b/common/route.cc index a60f1c41..fe2c05e4 100644 --- a/common/route.cc +++ b/common/route.cc @@ -79,14 +79,26 @@ struct RipupScoreboard void ripup_net(Context *ctx, IdString net_name) { auto net_info = ctx->nets.at(net_name); + std::vector pips; + std::vector wires; + + pips.reserve(net_info->wires.size()); + wires.reserve(net_info->wires.size()); for (auto &it : net_info->wires) { - if (it.second != PipId()) - ctx->unbindPip(it.second); - ctx->unbindWire(it.first); + if (it.second.pip != PipId()) + pips.push_back(it.second.pip); + else + wires.push_back(it.first); } - net_info->wires.clear(); + for (auto pip : pips) + ctx->unbindPip(pip); + + for (auto wire : wires) + ctx->unbindWire(wire); + + assert(net_info->wires.empty()); } struct Router @@ -147,7 +159,7 @@ struct Router if (!ctx->checkWireAvail(next_wire)) { if (!ripup) continue; - IdString ripupWireNet = ctx->getWireNet(next_wire, true); + IdString ripupWireNet = ctx->getConflictingWireNet(next_wire); if (ripupWireNet == net_name || ripupWireNet == IdString()) continue; auto it = scores.wireScores.find( @@ -160,7 +172,7 @@ struct Router if (!ctx->checkPipAvail(pip)) { if (!ripup) continue; - IdString ripupPipNet = ctx->getPipNet(pip, true); + IdString ripupPipNet = ctx->getConflictingPipNet(pip); if (ripupPipNet == net_name || ripupPipNet == IdString()) continue; auto it = scores.pipScores.find( @@ -280,8 +292,7 @@ struct Router std::unordered_map src_wires; src_wires[src_wire] = 0; - net_info->wires[src_wire] = PipId(); - ctx->bindWire(src_wire, net_name); + ctx->bindWire(src_wire, net_name, STRENGTH_WEAK); std::vector users_array = net_info->users; ctx->shuffle(users_array); @@ -361,9 +372,9 @@ struct Router if (src_wires.count(cursor)) break; - IdString conflicting_wire_net = ctx->getWireNet(cursor, true); + IdString conflicting_wire_net = ctx->getConflictingWireNet(cursor); IdString conflicting_pip_net = - ctx->getPipNet(visited[cursor].pip, true); + ctx->getConflictingPipNet(visited[cursor].pip); if (conflicting_wire_net != IdString()) { assert(ripup); @@ -388,10 +399,7 @@ struct Router visited[cursor].pip)]++; } - net_info->wires[cursor] = visited[cursor].pip; - ctx->bindWire(cursor, net_name); - ctx->bindPip(visited[cursor].pip, net_name); - + ctx->bindPip(visited[cursor].pip, net_name, STRENGTH_WEAK); src_wires[cursor] = visited[cursor].delay; cursor = ctx->getPipSrcWire(visited[cursor].pip); } @@ -495,6 +503,9 @@ bool route_design(Context *ctx) if (iterCnt == 200) { log_warning("giving up after %d iterations.\n", iterCnt); log_info("Checksum: 0x%08x\n", ctx->checksum()); +#ifndef NDEBUG + ctx->check(); +#endif return false; } @@ -655,8 +666,14 @@ bool route_design(Context *ctx) (100.0 * totalOvertimeRevisitCnt) / totalVisitCnt); log_info("Checksum: 0x%08x\n", ctx->checksum()); +#ifndef NDEBUG + ctx->check(); +#endif return true; } catch (log_execution_error_exception) { +#ifndef NDEBUG + ctx->check(); +#endif return false; } } diff --git a/dummy/arch.cc b/dummy/arch.cc index 64c0ca1e..4adff2ca 100644 --- a/dummy/arch.cc +++ b/dummy/arch.cc @@ -36,16 +36,15 @@ IdString Arch::getBelName(BelId bel) const { return IdString(); } uint32_t Arch::getBelChecksum(BelId bel) const { return 0; } -void Arch::bindBel(BelId bel, IdString cell) {} +void Arch::bindBel(BelId bel, IdString cell, PlaceStrength strength) {} void Arch::unbindBel(BelId bel) {} bool Arch::checkBelAvail(BelId bel) const { return false; } -IdString Arch::getBelCell(BelId bel, bool conflicting) const -{ - return IdString(); -} +IdString Arch::getBoundBelCell(BelId bel) const { return IdString(); } + +IdString Arch::getConflictingBelCell(BelId bel) const { return IdString(); } const std::vector &Arch::getBels() const { @@ -79,16 +78,15 @@ IdString Arch::getWireName(WireId wire) const { return IdString(); } uint32_t Arch::getWireChecksum(WireId wire) const { return 0; } -void Arch::bindWire(WireId wire, IdString net) {} +void Arch::bindWire(WireId wire, IdString net, PlaceStrength strength) {} void Arch::unbindWire(WireId wire) {} bool Arch::checkWireAvail(WireId wire) const { return false; } -IdString Arch::getWireNet(WireId wire, bool conflicting) const -{ - return IdString(); -} +IdString Arch::getBoundWireNet(WireId wire) const { return IdString(); } + +IdString Arch::getConflictingWireNet(WireId wire) const { return IdString(); } const std::vector &Arch::getWires() const { @@ -104,16 +102,15 @@ IdString Arch::getPipName(PipId pip) const { return IdString(); } uint32_t Arch::getPipChecksum(PipId wire) const { return 0; } -void Arch::bindPip(PipId pip, IdString net) {} +void Arch::bindPip(PipId pip, IdString net, PlaceStrength strength) {} void Arch::unbindPip(PipId pip) {} bool Arch::checkPipAvail(PipId pip) const { return false; } -IdString Arch::getPipNet(PipId pip, bool conflicting) const -{ - return IdString(); -} +IdString Arch::getBoundPipNet(PipId pip) const { return IdString(); } + +IdString Arch::getConflictingPipNet(PipId pip) const { return IdString(); } const std::vector &Arch::getPips() const { diff --git a/dummy/arch.h b/dummy/arch.h index 5bdf633e..2a778689 100644 --- a/dummy/arch.h +++ b/dummy/arch.h @@ -88,10 +88,11 @@ struct Arch : BaseCtx BelId getBelByName(IdString name) const; IdString getBelName(BelId bel) const; uint32_t getBelChecksum(BelId bel) const; - void bindBel(BelId bel, IdString cell); + void bindBel(BelId bel, IdString cell, PlaceStrength strength); void unbindBel(BelId bel); bool checkBelAvail(BelId bel) const; - IdString getBelCell(BelId bel, bool conflicting = false) const; + IdString getBoundBelCell(BelId bel) const; + IdString getConflictingBelCell(BelId bel) const; const std::vector &getBels() const; const std::vector &getBelsByType(BelType type) const; BelType getBelType(BelId bel) const; @@ -102,19 +103,21 @@ struct Arch : BaseCtx WireId getWireByName(IdString name) const; IdString getWireName(WireId wire) const; uint32_t getWireChecksum(WireId wire) const; - void bindWire(WireId wire, IdString net); + void bindWire(WireId wire, IdString net, PlaceStrength strength); void unbindWire(WireId wire); bool checkWireAvail(WireId wire) const; - IdString getWireNet(WireId wire, bool conflicting = false) const; + IdString getBoundWireNet(WireId wire) const; + IdString getConflictingWireNet(WireId wire) const; const std::vector &getWires() const; PipId getPipByName(IdString name) const; IdString getPipName(PipId pip) const; uint32_t getPipChecksum(PipId pip) const; - void bindPip(PipId pip, IdString net); + void bindPip(PipId pip, IdString net, PlaceStrength strength); void unbindPip(PipId pip); bool checkPipAvail(PipId pip) const; - IdString getPipNet(PipId pip, bool conflicting = false) const; + IdString getBoundPipNet(PipId pip) const; + IdString getConflictingPipNet(PipId pip) const; const std::vector &getPips() const; WireId getPipSrcWire(PipId pip) const; WireId getPipDstWire(PipId pip) const; diff --git a/ice40/arch.h b/ice40/arch.h index a6b70a69..26504cff 100644 --- a/ice40/arch.h +++ b/ice40/arch.h @@ -533,17 +533,21 @@ struct Arch : BaseCtx uint32_t getBelChecksum(BelId bel) const { return bel.index; } - void bindBel(BelId bel, IdString cell) + void bindBel(BelId bel, IdString cell, PlaceStrength strength) { assert(bel != BelId()); assert(bel_to_cell[bel.index] == IdString()); bel_to_cell[bel.index] = cell; + cells[cell]->bel = bel; + cells[cell]->belStrength = strength; } void unbindBel(BelId bel) { assert(bel != BelId()); assert(bel_to_cell[bel.index] != IdString()); + cells[bel_to_cell[bel.index]]->bel = BelId(); + cells[bel_to_cell[bel.index]]->belStrength = STRENGTH_NONE; bel_to_cell[bel.index] = IdString(); } @@ -553,7 +557,13 @@ struct Arch : BaseCtx return bel_to_cell[bel.index] == IdString(); } - IdString getBelCell(BelId bel, bool conflicting = false) const + IdString getBoundBelCell(BelId bel) const + { + assert(bel != BelId()); + return bel_to_cell[bel.index]; + } + + IdString getConflictingBelCell(BelId bel) const { assert(bel != BelId()); return bel_to_cell[bel.index]; @@ -627,17 +637,20 @@ struct Arch : BaseCtx uint32_t getWireChecksum(WireId wire) const { return wire.index; } - void bindWire(WireId wire, IdString net) + void bindWire(WireId wire, IdString net, PlaceStrength strength) { assert(wire != WireId()); assert(wire_to_net[wire.index] == IdString()); wire_to_net[wire.index] = net; + nets[net]->wires[wire].pip = PipId(); + nets[net]->wires[wire].strength = strength; } void unbindWire(WireId wire) { assert(wire != WireId()); assert(wire_to_net[wire.index] != IdString()); + nets[wire_to_net[wire.index]]->wires.erase(wire); wire_to_net[wire.index] = IdString(); } @@ -647,7 +660,13 @@ struct Arch : BaseCtx return wire_to_net[wire.index] == IdString(); } - IdString getWireNet(WireId wire, bool conflicting = false) const + IdString getBoundWireNet(WireId wire) const + { + assert(wire != WireId()); + return wire_to_net[wire.index]; + } + + IdString getConflictingWireNet(WireId wire) const { assert(wire != WireId()); return wire_to_net[wire.index]; @@ -668,14 +687,22 @@ struct Arch : BaseCtx uint32_t getPipChecksum(PipId pip) const { return pip.index; } - void bindPip(PipId pip, IdString net) + void bindPip(PipId pip, IdString net, PlaceStrength strength) { assert(pip != PipId()); assert(pip_to_net[pip.index] == IdString()); assert(switches_locked[chip_info->pip_data[pip.index].switch_index] == IdString()); + pip_to_net[pip.index] = net; switches_locked[chip_info->pip_data[pip.index].switch_index] = net; + + WireId dst; + dst.index = chip_info->pip_data[pip.index].dst; + assert(wire_to_net[dst.index] == IdString()); + wire_to_net[dst.index] = net; + nets[net]->wires[dst].pip = pip; + nets[net]->wires[dst].strength = strength; } void unbindPip(PipId pip) @@ -684,6 +711,13 @@ struct Arch : BaseCtx assert(pip_to_net[pip.index] != IdString()); assert(switches_locked[chip_info->pip_data[pip.index].switch_index] != IdString()); + + WireId dst; + dst.index = chip_info->pip_data[pip.index].dst; + assert(wire_to_net[dst.index] != IdString()); + wire_to_net[dst.index] = IdString(); + nets[pip_to_net[pip.index]]->wires.erase(dst); + pip_to_net[pip.index] = IdString(); switches_locked[chip_info->pip_data[pip.index].switch_index] = IdString(); @@ -696,14 +730,18 @@ struct Arch : BaseCtx IdString(); } - IdString getPipNet(PipId pip, bool conflicting = false) const + IdString getBoundPipNet(PipId pip) const { assert(pip != PipId()); - if (conflicting) - return switches_locked[chip_info->pip_data[pip.index].switch_index]; return pip_to_net[pip.index]; } + IdString getConflictingPipNet(PipId pip) const + { + assert(pip != PipId()); + return switches_locked[chip_info->pip_data[pip.index].switch_index]; + } + AllPipRange getPips() const { AllPipRange range; diff --git a/ice40/arch_place.cc b/ice40/arch_place.cc index 7b79e031..d374b764 100644 --- a/ice40/arch_place.cc +++ b/ice40/arch_place.cc @@ -102,7 +102,7 @@ bool PlaceValidityChecker::isBelLocationValid(BelId bel) if (ctx->getBelType(bel) == TYPE_ICESTORM_LC) { std::vector cells; for (auto bel_other : ctx->getBelsAtSameTile(bel)) { - IdString cell_other = ctx->getBelCell(bel_other, false); + IdString cell_other = ctx->getBoundBelCell(bel_other); if (cell_other != IdString()) { const CellInfo *ci_other = ctx->cells[cell_other]; cells.push_back(ci_other); @@ -110,7 +110,7 @@ bool PlaceValidityChecker::isBelLocationValid(BelId bel) } return logicCellsCompatible(ctx, cells); } else { - IdString cellId = ctx->getBelCell(bel, false); + IdString cellId = ctx->getBoundBelCell(bel); if (cellId == IdString()) return true; else @@ -126,7 +126,7 @@ bool PlaceValidityChecker::isValidBelForCell(CellInfo *cell, BelId bel) std::vector cells; for (auto bel_other : ctx->getBelsAtSameTile(bel)) { - IdString cell_other = ctx->getBelCell(bel_other, false); + IdString cell_other = ctx->getBoundBelCell(bel_other); if (cell_other != IdString()) { const CellInfo *ci_other = ctx->cells[cell_other]; cells.push_back(ci_other); diff --git a/ice40/bitstream.cc b/ice40/bitstream.cc index c46776a6..58c2e754 100644 --- a/ice40/bitstream.cc +++ b/ice40/bitstream.cc @@ -464,7 +464,7 @@ void write_asc(const Context *ctx, std::ostream &out) // Write symbols // const bool write_symbols = 1; for (auto wire : ctx->getWires()) { - IdString net = ctx->getWireNet(wire, false); + IdString net = ctx->getBoundWireNet(wire); if (net != IdString()) out << ".sym " << wire.index << " " << net.str(ctx) << std::endl; }