diff options
Diffstat (limited to 'ice40')
-rw-r--r-- | ice40/arch.cc | 305 | ||||
-rw-r--r-- | ice40/arch.h | 309 | ||||
-rw-r--r-- | ice40/arch_place.cc | 69 | ||||
-rw-r--r-- | ice40/arch_pybindings.cc | 32 | ||||
-rw-r--r-- | ice40/arch_pybindings.h | 18 | ||||
-rw-r--r-- | ice40/bitstream.cc | 13 | ||||
-rw-r--r-- | ice40/main.cc | 24 | ||||
-rw-r--r-- | ice40/place_legaliser.cc | 73 |
8 files changed, 367 insertions, 476 deletions
diff --git a/ice40/arch.cc b/ice40/arch.cc index 4727597b..adc37dbd 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -2,7 +2,6 @@ * nextpnr -- Next Generation Place and Route * * Copyright (C) 2018 Clifford Wolf <clifford@symbioticeda.com> - * Copyright (C) 2018 Serge Bazanski <q3k@symbioticeda.com> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -29,6 +28,8 @@ NEXTPNR_NAMESPACE_BEGIN +// ----------------------------------------------------------------------- + IdString Arch::belTypeToId(BelType type) const { if (type == TYPE_ICESTORM_LC) @@ -238,6 +239,22 @@ IdString Arch::archArgsToId(ArchArgs args) const // ----------------------------------------------------------------------- +BelId Arch::getBelByName(IdString name) const +{ + BelId ret; + + if (bel_by_name.empty()) { + for (int i = 0; i < chip_info->num_bels; i++) + bel_by_name[id(chip_info->bel_data[i].name.get())] = i; + } + + auto it = bel_by_name.find(name); + if (it != bel_by_name.end()) + ret.index = it->second; + + return ret; +} + BelRange Arch::getBelsAtSameTile(BelId bel) const { BelRange br; @@ -256,8 +273,63 @@ BelRange Arch::getBelsAtSameTile(BelId bel) const return br; } +WireId Arch::getWireBelPin(BelId bel, PortPin pin) const +{ + WireId ret; + + NPNR_ASSERT(bel != BelId()); + + int num_bel_wires = chip_info->bel_data[bel.index].num_bel_wires; + const BelWirePOD *bel_wires = chip_info->bel_data[bel.index].bel_wires.get(); + + for (int i = 0; i < num_bel_wires; i++) + if (bel_wires[i].port == pin) { + ret.index = bel_wires[i].wire_index; + break; + } + + return ret; +} + // ----------------------------------------------------------------------- +WireId Arch::getWireByName(IdString name) const +{ + WireId ret; + + if (wire_by_name.empty()) { + for (int i = 0; i < chip_info->num_wires; i++) + wire_by_name[id(chip_info->wire_data[i].name.get())] = i; + } + + auto it = wire_by_name.find(name); + if (it != wire_by_name.end()) + ret.index = it->second; + + return ret; +} + +// ----------------------------------------------------------------------- + +PipId Arch::getPipByName(IdString name) const +{ + PipId ret; + + if (pip_by_name.empty()) { + for (int i = 0; i < chip_info->num_pips; i++) { + PipId pip; + pip.index = i; + pip_by_name[getPipName(pip)] = i; + } + } + + auto it = pip_by_name.find(name); + if (it != pip_by_name.end()) + ret.index = it->second; + + return ret; +} + IdString Arch::getPipName(PipId pip) const { NPNR_ASSERT(pip != PipId()); @@ -300,8 +372,6 @@ std::string Arch::getBelPackagePin(BelId bel) const // ----------------------------------------------------------------------- -// TODO(cliffordvienna): lock all of this - GroupId Arch::getGroupByName(IdString name) const { for (auto g : getGroups()) @@ -425,7 +495,7 @@ DecalXY Arch::getGroupDecal(GroupId group) const return decalxy; }; -std::vector<GraphicElement> ArchReadMethods::getDecalGraphics(DecalId decal) const +std::vector<GraphicElement> Arch::getDecalGraphics(DecalId decal) const { std::vector<GraphicElement> ret; @@ -458,7 +528,7 @@ std::vector<GraphicElement> ArchReadMethods::getDecalGraphics(DecalId decal) con BelId bel; bel.index = decal.index; - auto bel_type = parent_->getBelType(bel); + auto bel_type = getBelType(bel); if (bel_type == TYPE_ICESTORM_LC) { GraphicElement el; @@ -533,7 +603,8 @@ std::vector<GraphicElement> ArchReadMethods::getDecalGraphics(DecalId decal) con } if (bel_type == TYPE_ICESTORM_RAM) { - for (int i = 0; i < 2; i++) { + for (int i = 0; i < 2; i++) + { int tx = chip_info->bel_data[bel.index].x; int ty = chip_info->bel_data[bel.index].y + i; @@ -543,7 +614,7 @@ std::vector<GraphicElement> ArchReadMethods::getDecalGraphics(DecalId decal) con el.x1 = chip_info->bel_data[bel.index].x + logic_cell_x1; el.x2 = chip_info->bel_data[bel.index].x + logic_cell_x2; el.y1 = chip_info->bel_data[bel.index].y + logic_cell_y1; - el.y2 = chip_info->bel_data[bel.index].y + logic_cell_y2 + 7 * logic_cell_pitch; + el.y2 = chip_info->bel_data[bel.index].y + logic_cell_y2 + 7*logic_cell_pitch; el.z = 0; ret.push_back(el); @@ -620,224 +691,4 @@ bool Arch::isGlobalNet(const NetInfo *net) const return net->driver.cell != nullptr && net->driver.port == id_glb_buf_out; } -// ----------------------------------------------------------------------- - -bool ArchReadMethods::checkBelAvail(BelId bel) const -{ - NPNR_ASSERT(bel != BelId()); - return bel_to_cell[bel.index] == IdString(); -} - -IdString ArchReadMethods::getBoundBelCell(BelId bel) const -{ - NPNR_ASSERT(bel != BelId()); - return bel_to_cell[bel.index]; -} - -IdString ArchReadMethods::getConflictingBelCell(BelId bel) const -{ - NPNR_ASSERT(bel != BelId()); - return bel_to_cell[bel.index]; -} - -WireId ArchReadMethods::getWireBelPin(BelId bel, PortPin pin) const -{ - WireId ret; - - NPNR_ASSERT(bel != BelId()); - - int num_bel_wires = chip_info->bel_data[bel.index].num_bel_wires; - const BelWirePOD *bel_wires = chip_info->bel_data[bel.index].bel_wires.get(); - - for (int i = 0; i < num_bel_wires; i++) - if (bel_wires[i].port == pin) { - ret.index = bel_wires[i].wire_index; - break; - } - - return ret; -} - -WireId ArchReadMethods::getWireByName(IdString name) const -{ - WireId ret; - - if (wire_by_name.empty()) { - for (int i = 0; i < chip_info->num_wires; i++) - wire_by_name[parent_->id(chip_info->wire_data[i].name.get())] = i; - } - - auto it = wire_by_name.find(name); - if (it != wire_by_name.end()) - ret.index = it->second; - - return ret; -} - -bool ArchReadMethods::checkWireAvail(WireId wire) const -{ - NPNR_ASSERT(wire != WireId()); - return wire_to_net[wire.index] == IdString(); -} - -IdString ArchReadMethods::getBoundWireNet(WireId wire) const -{ - NPNR_ASSERT(wire != WireId()); - return wire_to_net[wire.index]; -} - -IdString ArchReadMethods::getConflictingWireNet(WireId wire) const -{ - NPNR_ASSERT(wire != WireId()); - return wire_to_net[wire.index]; -} - -PipId ArchReadMethods::getPipByName(IdString name) const -{ - PipId ret; - - if (pip_by_name.empty()) { - for (int i = 0; i < chip_info->num_pips; i++) { - PipId pip; - pip.index = i; - pip_by_name[parent_->getPipName(pip)] = i; - } - } - - auto it = pip_by_name.find(name); - if (it != pip_by_name.end()) - ret.index = it->second; - - return ret; -} - -bool ArchReadMethods::checkPipAvail(PipId pip) const -{ - NPNR_ASSERT(pip != PipId()); - return switches_locked[chip_info->pip_data[pip.index].switch_index] == IdString(); -} - -IdString ArchReadMethods::getBoundPipNet(PipId pip) const -{ - NPNR_ASSERT(pip != PipId()); - return pip_to_net[pip.index]; -} - -IdString ArchReadMethods::getConflictingPipNet(PipId pip) const -{ - NPNR_ASSERT(pip != PipId()); - return switches_locked[chip_info->pip_data[pip.index].switch_index]; -} - -BelId ArchReadMethods::getBelByName(IdString name) const -{ - BelId ret; - - if (bel_by_name.empty()) { - for (int i = 0; i < chip_info->num_bels; i++) - bel_by_name[parent_->id(chip_info->bel_data[i].name.get())] = i; - } - - auto it = bel_by_name.find(name); - if (it != bel_by_name.end()) - ret.index = it->second; - - return ret; -} - -// ----------------------------------------------------------------------- - -void ArchMutateMethods::bindBel(BelId bel, IdString cell, PlaceStrength strength) -{ - NPNR_ASSERT(bel != BelId()); - NPNR_ASSERT(bel_to_cell[bel.index] == IdString()); - bel_to_cell[bel.index] = cell; - parent_->cells[cell]->bel = bel; - parent_->cells[cell]->belStrength = strength; - refreshUiBel(bel); -} - -void ArchMutateMethods::unbindBel(BelId bel) -{ - NPNR_ASSERT(bel != BelId()); - NPNR_ASSERT(bel_to_cell[bel.index] != IdString()); - parent_->cells[bel_to_cell[bel.index]]->bel = BelId(); - parent_->cells[bel_to_cell[bel.index]]->belStrength = STRENGTH_NONE; - bel_to_cell[bel.index] = IdString(); - refreshUiBel(bel); -} - -void ArchMutateMethods::bindWire(WireId wire, IdString net, PlaceStrength strength) -{ - NPNR_ASSERT(wire != WireId()); - NPNR_ASSERT(wire_to_net[wire.index] == IdString()); - - wire_to_net[wire.index] = net; - parent_->nets[net]->wires[wire].pip = PipId(); - parent_->nets[net]->wires[wire].strength = strength; - refreshUiWire(wire); -} - -void ArchMutateMethods::unbindWire(WireId wire) -{ - NPNR_ASSERT(wire != WireId()); - NPNR_ASSERT(wire_to_net[wire.index] != IdString()); - - auto &net_wires = parent_->nets[wire_to_net[wire.index]]->wires; - auto it = net_wires.find(wire); - NPNR_ASSERT(it != net_wires.end()); - - auto pip = it->second.pip; - if (pip != PipId()) { - pip_to_net[pip.index] = IdString(); - switches_locked[chip_info->pip_data[pip.index].switch_index] = IdString(); - refreshUiPip(pip); - } - - net_wires.erase(it); - wire_to_net[wire.index] = IdString(); - refreshUiWire(wire); -} - -void ArchMutateMethods::bindPip(PipId pip, IdString net, PlaceStrength strength) -{ - NPNR_ASSERT(pip != PipId()); - NPNR_ASSERT(pip_to_net[pip.index] == IdString()); - NPNR_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; - NPNR_ASSERT(wire_to_net[dst.index] == IdString()); - wire_to_net[dst.index] = net; - parent_->nets[net]->wires[dst].pip = pip; - parent_->nets[net]->wires[dst].strength = strength; - - refreshUiPip(pip); - refreshUiWire(dst); -} - -void ArchMutateMethods::unbindPip(PipId pip) -{ - NPNR_ASSERT(pip != PipId()); - NPNR_ASSERT(pip_to_net[pip.index] != IdString()); - NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] != IdString()); - - WireId dst; - dst.index = chip_info->pip_data[pip.index].dst; - NPNR_ASSERT(wire_to_net[dst.index] != IdString()); - wire_to_net[dst.index] = IdString(); - parent_->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(); - - refreshUiPip(pip); - refreshUiWire(dst); -} - -CellInfo *ArchMutateMethods::getCell(IdString cell) { return parent_->cells.at(cell).get(); } - NEXTPNR_NAMESPACE_END diff --git a/ice40/arch.h b/ice40/arch.h index 25ed8ebf..a02e0ced 100644 --- a/ice40/arch.h +++ b/ice40/arch.h @@ -2,7 +2,6 @@ * nextpnr -- Next Generation Place and Route * * Copyright (C) 2018 Clifford Wolf <clifford@symbioticeda.com> - * Copyright (C) 2018 Serge Bazanski <q3k@symbioticeda.com> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -325,37 +324,19 @@ struct ArchArgs std::string package; }; -/// Forward declare proxy classes for Arch. - -class ArchMutateMethods; -class ArchReadMethods; - -/// Arch/Context -// Arch is the main state class of the PnR algorithms. It keeps note of mapped -// cells/nets, locked switches, etc. -// -// In order to mutate state in Arch, you can do one of two things: -// - directly call one of the wrapper methods to mutate state -// - get a read or readwrite proxy to the Arch, and call methods on it - -class Arch : public BaseCtx +struct Arch : BaseCtx { - // We let proxy methods access our state. - friend class ArchMutateMethods; - friend class ArchReadMethods; + const ChipInfoPOD *chip_info; + const PackageInfoPOD *package_info; - private: - std::vector<IdString> bel_to_cell; - std::vector<IdString> wire_to_net; - std::vector<IdString> pip_to_net; - std::vector<IdString> switches_locked; mutable std::unordered_map<IdString, int> bel_by_name; mutable std::unordered_map<IdString, int> wire_by_name; mutable std::unordered_map<IdString, int> pip_by_name; - public: - const ChipInfoPOD *chip_info; - const PackageInfoPOD *package_info; + std::vector<IdString> bel_to_cell; + std::vector<IdString> wire_to_net; + std::vector<IdString> pip_to_net; + std::vector<IdString> switches_locked; ArchArgs args; Arch(ArchArgs args); @@ -373,8 +354,7 @@ class Arch : public BaseCtx // ------------------------------------------------- - /// Methods to get chip info - don't need to use a wrapper, as these are - /// static per lifetime of object. + BelId getBelByName(IdString name) const; IdString getBelName(BelId bel) const { @@ -384,6 +364,42 @@ class Arch : public BaseCtx uint32_t getBelChecksum(BelId bel) const { return bel.index; } + void bindBel(BelId bel, IdString cell, PlaceStrength strength) + { + NPNR_ASSERT(bel != BelId()); + NPNR_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) + { + NPNR_ASSERT(bel != BelId()); + NPNR_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(); + } + + bool checkBelAvail(BelId bel) const + { + NPNR_ASSERT(bel != BelId()); + return bel_to_cell[bel.index] == IdString(); + } + + IdString getBoundBelCell(BelId bel) const + { + NPNR_ASSERT(bel != BelId()); + return bel_to_cell[bel.index]; + } + + IdString getConflictingBelCell(BelId bel) const + { + NPNR_ASSERT(bel != BelId()); + return bel_to_cell[bel.index]; + } + BelRange getBels() const { BelRange range; @@ -397,11 +413,11 @@ class Arch : public BaseCtx BelRange range; // FIXME #if 0 - if (type == "TYPE_A") { - range.b.cursor = bels_type_a_begin; - range.e.cursor = bels_type_a_end; - } - ... + if (type == "TYPE_A") { + range.b.cursor = bels_type_a_begin; + range.e.cursor = bels_type_a_end; + } + ... #endif return range; } @@ -414,6 +430,8 @@ class Arch : public BaseCtx return chip_info->bel_data[bel.index].type; } + WireId getWireBelPin(BelId bel, PortPin pin) const; + BelPin getBelPinUphill(WireId wire) const { BelPin ret; @@ -438,6 +456,8 @@ class Arch : public BaseCtx // ------------------------------------------------- + WireId getWireByName(IdString name) const; + IdString getWireName(WireId wire) const { NPNR_ASSERT(wire != WireId()); @@ -446,6 +466,115 @@ class Arch : public BaseCtx uint32_t getWireChecksum(WireId wire) const { return wire.index; } + void bindWire(WireId wire, IdString net, PlaceStrength strength) + { + NPNR_ASSERT(wire != WireId()); + NPNR_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) + { + NPNR_ASSERT(wire != WireId()); + NPNR_ASSERT(wire_to_net[wire.index] != IdString()); + + auto &net_wires = nets[wire_to_net[wire.index]]->wires; + auto it = net_wires.find(wire); + NPNR_ASSERT(it != net_wires.end()); + + auto pip = it->second.pip; + if (pip != PipId()) { + pip_to_net[pip.index] = IdString(); + switches_locked[chip_info->pip_data[pip.index].switch_index] = IdString(); + } + + net_wires.erase(it); + wire_to_net[wire.index] = IdString(); + } + + bool checkWireAvail(WireId wire) const + { + NPNR_ASSERT(wire != WireId()); + return wire_to_net[wire.index] == IdString(); + } + + IdString getBoundWireNet(WireId wire) const + { + NPNR_ASSERT(wire != WireId()); + return wire_to_net[wire.index]; + } + + IdString getConflictingWireNet(WireId wire) const + { + NPNR_ASSERT(wire != WireId()); + return wire_to_net[wire.index]; + } + + WireRange getWires() const + { + WireRange range; + range.b.cursor = 0; + range.e.cursor = chip_info->num_wires; + return range; + } + + // ------------------------------------------------- + + PipId getPipByName(IdString name) const; + + void bindPip(PipId pip, IdString net, PlaceStrength strength) + { + NPNR_ASSERT(pip != PipId()); + NPNR_ASSERT(pip_to_net[pip.index] == IdString()); + NPNR_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; + NPNR_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) + { + NPNR_ASSERT(pip != PipId()); + NPNR_ASSERT(pip_to_net[pip.index] != IdString()); + NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] != IdString()); + + WireId dst; + dst.index = chip_info->pip_data[pip.index].dst; + NPNR_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(); + } + + bool checkPipAvail(PipId pip) const + { + NPNR_ASSERT(pip != PipId()); + return switches_locked[chip_info->pip_data[pip.index].switch_index] == IdString(); + } + + IdString getBoundPipNet(PipId pip) const + { + NPNR_ASSERT(pip != PipId()); + return pip_to_net[pip.index]; + } + + IdString getConflictingPipNet(PipId pip) const + { + NPNR_ASSERT(pip != PipId()); + return switches_locked[chip_info->pip_data[pip.index].switch_index]; + } + AllPipRange getPips() const { AllPipRange range; @@ -453,7 +582,7 @@ class Arch : public BaseCtx range.e.cursor = chip_info->num_pips; return range; } - + IdString getPipName(PipId pip) const; uint32_t getPipChecksum(PipId pip) const { return pip.index; } @@ -509,20 +638,11 @@ class Arch : public BaseCtx return range; } - WireRange getWires() const - { - WireRange range; - range.b.cursor = 0; - range.e.cursor = chip_info->num_wires; - return range; - } - BelId getPackagePinBel(const std::string &pin) const; std::string getBelPackagePin(BelId bel) const; // ------------------------------------------------- - // TODO(q3k) move this to archproxies? GroupId getGroupByName(IdString name) const; IdString getGroupName(GroupId group) const; std::vector<GroupId> getGroups() const; @@ -533,8 +653,6 @@ class Arch : public BaseCtx // ------------------------------------------------- - // These are also specific to the chip and not state, so they're available - // on arch directly. void estimatePosition(BelId bel, int &x, int &y, bool &gb) const; delay_t estimateDelay(WireId src, WireId dst) const; delay_t getDelayEpsilon() const { return 20; } @@ -550,7 +668,8 @@ class Arch : public BaseCtx // ------------------------------------------------- - // TODO(q3k) move this to archproxies? + std::vector<GraphicElement> getDecalGraphics(DecalId decal) const; + DecalXY getFrameDecal() const; DecalXY getBelDecal(BelId bel) const; DecalXY getWireDecal(WireId wire) const; @@ -571,106 +690,24 @@ class Arch : public BaseCtx // ------------------------------------------------- - IdString id_glb_buf_out; - IdString id_icestorm_lc, id_sb_io, id_sb_gb; - IdString id_cen, id_clk, id_sr; - IdString id_i0, id_i1, id_i2, id_i3; - IdString id_dff_en, id_neg_clk; -}; + // Perform placement validity checks, returning false on failure (all implemented in arch_place.cc) -// Read-only methods on Arch that require state access. -class ArchReadMethods : public BaseReadCtx -{ - private: - const Arch *parent_; - const ChipInfoPOD *chip_info; - const std::vector<IdString> &bel_to_cell; - const std::vector<IdString> &wire_to_net; - const std::vector<IdString> &pip_to_net; - const std::vector<IdString> &switches_locked; - std::unordered_map<IdString, int> &bel_by_name; - std::unordered_map<IdString, int> &wire_by_name; - std::unordered_map<IdString, int> &pip_by_name; - - public: - ~ArchReadMethods() noexcept {} - ArchReadMethods(const Arch *parent) - : BaseReadCtx(parent), parent_(parent), chip_info(parent->chip_info), bel_to_cell(parent->bel_to_cell), - wire_to_net(parent->wire_to_net), pip_to_net(parent->pip_to_net), - switches_locked(parent->switches_locked), bel_by_name(parent->bel_by_name), - wire_by_name(parent->wire_by_name), pip_by_name(parent->pip_by_name) - { - } - ArchReadMethods(ArchReadMethods &&other) noexcept : ArchReadMethods(other.parent_) {} - ArchReadMethods(const ArchReadMethods &other) : ArchReadMethods(other.parent_) {} - - /// Perform placement validity checks, returning false on failure (all implemented in arch_place.cc) // Whether or not a given cell can be placed at a given Bel // This is not intended for Bel type checks, but finer-grained constraints // such as conflicting set/reset signals, etc bool isValidBelForCell(CellInfo *cell, BelId bel) const; + // Return true whether all Bels at a given location are valid bool isBelLocationValid(BelId bel) const; + // Helper function for above bool logicCellsCompatible(const std::vector<const CellInfo *> &cells) const; - bool checkWireAvail(WireId wire) const; - bool checkPipAvail(PipId pip) const; - bool checkBelAvail(BelId bel) const; - - WireId getWireByName(IdString name) const; - WireId getWireBelPin(BelId bel, PortPin pin) const; - PipId getPipByName(IdString name) const; - - IdString getConflictingWireNet(WireId wire) const; - IdString getConflictingPipNet(PipId pip) const; - IdString getConflictingBelCell(BelId bel) const; - - IdString getBoundWireNet(WireId wire) const; - IdString getBoundPipNet(PipId pip) const; - IdString getBoundBelCell(BelId bel) const; - - BelId getBelByName(IdString name) const; - - std::vector<GraphicElement> getDecalGraphics(DecalId decal) const; -}; - -// State mutating methods on Arch. -class ArchMutateMethods : public BaseMutateCtx -{ - friend class MutateContext; - - private: - Arch *parent_; - const ChipInfoPOD *chip_info; - std::vector<IdString> &bel_to_cell; - std::vector<IdString> &wire_to_net; - std::vector<IdString> &pip_to_net; - std::vector<IdString> &switches_locked; - std::unordered_map<IdString, int> &bel_by_name; - std::unordered_map<IdString, int> &wire_by_name; - std::unordered_map<IdString, int> &pip_by_name; - - public: - ArchMutateMethods(Arch *parent) - : BaseMutateCtx(parent), parent_(parent), chip_info(parent->chip_info), bel_to_cell(parent->bel_to_cell), - wire_to_net(parent->wire_to_net), pip_to_net(parent->pip_to_net), - switches_locked(parent->switches_locked), bel_by_name(parent->bel_by_name), - wire_by_name(parent->wire_by_name), pip_by_name(parent->pip_by_name) - { - } - ArchMutateMethods(ArchMutateMethods &&other) : ArchMutateMethods(other.parent_) {} - ArchMutateMethods(const ArchMutateMethods &other) : ArchMutateMethods(other.parent_) {} - ~ArchMutateMethods() {} - - void unbindWire(WireId wire); - void unbindPip(PipId pip); - void unbindBel(BelId bel); - void bindWire(WireId wire, IdString net, PlaceStrength strength); - void bindPip(PipId pip, IdString net, PlaceStrength strength); - void bindBel(BelId bel, IdString cell, PlaceStrength strength); - // Returned pointer is valid as long as Proxy object exists. - CellInfo *getCell(IdString cell); + IdString id_glb_buf_out; + IdString id_icestorm_lc, id_sb_io, id_sb_gb; + IdString id_cen, id_clk, id_sr; + IdString id_i0, id_i1, id_i2, id_i3; + IdString id_dff_en, id_neg_clk; }; NEXTPNR_NAMESPACE_END diff --git a/ice40/arch_place.cc b/ice40/arch_place.cc index 42efceab..dc1bc3eb 100644 --- a/ice40/arch_place.cc +++ b/ice40/arch_place.cc @@ -3,7 +3,6 @@ * * Copyright (C) 2018 Clifford Wolf <clifford@symbioticeda.com> * Copyright (C) 2018 David Shah <david@symbioticeda.com> - * Copyright (C) 2018 Serge Bazanski <q3k@symbioticeda.com> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -25,44 +24,44 @@ NEXTPNR_NAMESPACE_BEGIN -bool ArchReadMethods::logicCellsCompatible(const std::vector<const CellInfo *> &cells) const +bool Arch::logicCellsCompatible(const std::vector<const CellInfo *> &cells) const { bool dffs_exist = false, dffs_neg = false; const NetInfo *cen = nullptr, *clk = nullptr, *sr = nullptr; int locals_count = 0; for (auto cell : cells) { - if (bool_or_default(cell->params, parent_->id_dff_en)) { + if (bool_or_default(cell->params, id_dff_en)) { if (!dffs_exist) { dffs_exist = true; - cen = get_net_or_empty(cell, parent_->id_cen); - clk = get_net_or_empty(cell, parent_->id_clk); - sr = get_net_or_empty(cell, parent_->id_sr); + cen = get_net_or_empty(cell, id_cen); + clk = get_net_or_empty(cell, id_clk); + sr = get_net_or_empty(cell, id_sr); - if (!parent_->isGlobalNet(cen) && cen != nullptr) + if (!isGlobalNet(cen) && cen != nullptr) locals_count++; - if (!parent_->isGlobalNet(clk) && clk != nullptr) + if (!isGlobalNet(clk) && clk != nullptr) locals_count++; - if (!parent_->isGlobalNet(sr) && sr != nullptr) + if (!isGlobalNet(sr) && sr != nullptr) locals_count++; - if (bool_or_default(cell->params, parent_->id_neg_clk)) { + if (bool_or_default(cell->params, id_neg_clk)) { dffs_neg = true; } } else { - if (cen != get_net_or_empty(cell, parent_->id_cen)) + if (cen != get_net_or_empty(cell, id_cen)) return false; - if (clk != get_net_or_empty(cell, parent_->id_clk)) + if (clk != get_net_or_empty(cell, id_clk)) return false; - if (sr != get_net_or_empty(cell, parent_->id_sr)) + if (sr != get_net_or_empty(cell, id_sr)) return false; - if (dffs_neg != bool_or_default(cell->params, parent_->id_neg_clk)) + if (dffs_neg != bool_or_default(cell->params, id_neg_clk)) return false; } } - const NetInfo *i0 = get_net_or_empty(cell, parent_->id_i0), *i1 = get_net_or_empty(cell, parent_->id_i1), - *i2 = get_net_or_empty(cell, parent_->id_i2), *i3 = get_net_or_empty(cell, parent_->id_i3); + const NetInfo *i0 = get_net_or_empty(cell, id_i0), *i1 = get_net_or_empty(cell, id_i1), + *i2 = get_net_or_empty(cell, id_i2), *i3 = get_net_or_empty(cell, id_i3); if (i0 != nullptr) locals_count++; if (i1 != nullptr) @@ -76,14 +75,14 @@ bool ArchReadMethods::logicCellsCompatible(const std::vector<const CellInfo *> & return locals_count <= 32; } -bool ArchReadMethods::isBelLocationValid(BelId bel) const +bool Arch::isBelLocationValid(BelId bel) const { - if (parent_->getBelType(bel) == TYPE_ICESTORM_LC) { + if (getBelType(bel) == TYPE_ICESTORM_LC) { std::vector<const CellInfo *> bel_cells; - for (auto bel_other : parent_->getBelsAtSameTile(bel)) { + for (auto bel_other : getBelsAtSameTile(bel)) { IdString cell_other = getBoundBelCell(bel_other); if (cell_other != IdString()) { - const CellInfo *ci_other = parent_->cells.at(cell_other).get(); + const CellInfo *ci_other = cells.at(cell_other).get(); bel_cells.push_back(ci_other); } } @@ -93,40 +92,40 @@ bool ArchReadMethods::isBelLocationValid(BelId bel) const if (cellId == IdString()) return true; else - return isValidBelForCell(parent_->cells.at(cellId).get(), bel); + return isValidBelForCell(cells.at(cellId).get(), bel); } } -bool ArchReadMethods::isValidBelForCell(CellInfo *cell, BelId bel) const +bool Arch::isValidBelForCell(CellInfo *cell, BelId bel) const { - if (cell->type == parent_->id_icestorm_lc) { - NPNR_ASSERT(parent_->getBelType(bel) == TYPE_ICESTORM_LC); + if (cell->type == id_icestorm_lc) { + NPNR_ASSERT(getBelType(bel) == TYPE_ICESTORM_LC); std::vector<const CellInfo *> bel_cells; - for (auto bel_other : parent_->getBelsAtSameTile(bel)) { + for (auto bel_other : getBelsAtSameTile(bel)) { IdString cell_other = getBoundBelCell(bel_other); if (cell_other != IdString() && bel_other != bel) { - const CellInfo *ci_other = parent_->cells.at(cell_other).get(); + const CellInfo *ci_other = cells.at(cell_other).get(); bel_cells.push_back(ci_other); } } bel_cells.push_back(cell); return logicCellsCompatible(bel_cells); - } else if (cell->type == parent_->id_sb_io) { - return parent_->getBelPackagePin(bel) != ""; - } else if (cell->type == parent_->id_sb_gb) { + } else if (cell->type == id_sb_io) { + return getBelPackagePin(bel) != ""; + } else if (cell->type == id_sb_gb) { bool is_reset = false, is_cen = false; - NPNR_ASSERT(cell->ports.at(parent_->id_glb_buf_out).net != nullptr); - for (auto user : cell->ports.at(parent_->id_glb_buf_out).net->users) { - if (is_reset_port(parent_, user)) + NPNR_ASSERT(cell->ports.at(id_glb_buf_out).net != nullptr); + for (auto user : cell->ports.at(id_glb_buf_out).net->users) { + if (is_reset_port(this, user)) is_reset = true; - if (is_enable_port(parent_, user)) + if (is_enable_port(this, user)) is_cen = true; } - IdString glb_net = parent_->getWireName(getWireBelPin(bel, PIN_GLOBAL_BUFFER_OUTPUT)); - int glb_id = std::stoi(std::string("") + glb_net.str(parent_).back()); + IdString glb_net = getWireName(getWireBelPin(bel, PIN_GLOBAL_BUFFER_OUTPUT)); + int glb_id = std::stoi(std::string("") + glb_net.str(this).back()); if (is_reset && is_cen) return false; else if (is_reset) diff --git a/ice40/arch_pybindings.cc b/ice40/arch_pybindings.cc index a2a90191..fd5109b4 100644 --- a/ice40/arch_pybindings.cc +++ b/ice40/arch_pybindings.cc @@ -65,13 +65,25 @@ void arch_wrap_python() fn_wrapper_1a<Context, decltype(&Context::getBelType), &Context::getBelType, conv_to_str<BelType>, conv_from_str<BelId>>::def_wrap(ctx_cls, "getBelType"); + fn_wrapper_1a<Context, decltype(&Context::checkBelAvail), &Context::checkBelAvail, pass_through<bool>, + conv_from_str<BelId>>::def_wrap(ctx_cls, "checkBelAvail"); fn_wrapper_1a<Context, decltype(&Context::getBelChecksum), &Context::getBelChecksum, pass_through<uint32_t>, conv_from_str<BelId>>::def_wrap(ctx_cls, "getBelChecksum"); + fn_wrapper_3a_v<Context, decltype(&Context::bindBel), &Context::bindBel, conv_from_str<BelId>, + conv_from_str<IdString>, pass_through<PlaceStrength>>::def_wrap(ctx_cls, "bindBel"); + fn_wrapper_1a_v<Context, decltype(&Context::unbindBel), &Context::unbindBel, conv_from_str<BelId>>::def_wrap( + ctx_cls, "unbindBel"); + fn_wrapper_1a<Context, decltype(&Context::getBoundBelCell), &Context::getBoundBelCell, conv_to_str<IdString>, + conv_from_str<BelId>>::def_wrap(ctx_cls, "getBoundBelCell"); + fn_wrapper_1a<Context, decltype(&Context::getConflictingBelCell), &Context::getConflictingBelCell, + conv_to_str<IdString>, conv_from_str<BelId>>::def_wrap(ctx_cls, "getConflictingBelCell"); fn_wrapper_0a<Context, decltype(&Context::getBels), &Context::getBels, wrap_context<BelRange>>::def_wrap(ctx_cls, "getBels"); fn_wrapper_1a<Context, decltype(&Context::getBelsAtSameTile), &Context::getBelsAtSameTile, wrap_context<BelRange>, conv_from_str<BelId>>::def_wrap(ctx_cls, "getBelsAtSameTile"); + fn_wrapper_2a<Context, decltype(&Context::getWireBelPin), &Context::getWireBelPin, conv_to_str<WireId>, + conv_from_str<BelId>, conv_from_str<PortPin>>::def_wrap(ctx_cls, "getWireBelPin"); fn_wrapper_1a<Context, decltype(&Context::getBelPinUphill), &Context::getBelPinUphill, wrap_context<BelPin>, conv_from_str<WireId>>::def_wrap(ctx_cls, "getBelPinUphill"); fn_wrapper_1a<Context, decltype(&Context::getBelPinsDownhill), &Context::getBelPinsDownhill, @@ -79,6 +91,16 @@ void arch_wrap_python() fn_wrapper_1a<Context, decltype(&Context::getWireChecksum), &Context::getWireChecksum, pass_through<uint32_t>, conv_from_str<WireId>>::def_wrap(ctx_cls, "getWireChecksum"); + fn_wrapper_3a_v<Context, decltype(&Context::bindWire), &Context::bindWire, conv_from_str<WireId>, + conv_from_str<IdString>, pass_through<PlaceStrength>>::def_wrap(ctx_cls, "bindWire"); + fn_wrapper_1a_v<Context, decltype(&Context::unbindWire), &Context::unbindWire, conv_from_str<WireId>>::def_wrap( + ctx_cls, "unbindWire"); + fn_wrapper_1a<Context, decltype(&Context::checkWireAvail), &Context::checkWireAvail, pass_through<bool>, + conv_from_str<WireId>>::def_wrap(ctx_cls, "checkWireAvail"); + fn_wrapper_1a<Context, decltype(&Context::getBoundWireNet), &Context::getBoundWireNet, conv_to_str<IdString>, + conv_from_str<WireId>>::def_wrap(ctx_cls, "getBoundWireNet"); + fn_wrapper_1a<Context, decltype(&Context::getConflictingWireNet), &Context::getConflictingWireNet, + conv_to_str<IdString>, conv_from_str<WireId>>::def_wrap(ctx_cls, "getConflictingWireNet"); fn_wrapper_0a<Context, decltype(&Context::getWires), &Context::getWires, wrap_context<WireRange>>::def_wrap( ctx_cls, "getWires"); @@ -87,6 +109,16 @@ void arch_wrap_python() ctx_cls, "getPips"); fn_wrapper_1a<Context, decltype(&Context::getPipChecksum), &Context::getPipChecksum, pass_through<uint32_t>, conv_from_str<PipId>>::def_wrap(ctx_cls, "getPipChecksum"); + fn_wrapper_3a_v<Context, decltype(&Context::bindPip), &Context::bindPip, conv_from_str<PipId>, + conv_from_str<IdString>, pass_through<PlaceStrength>>::def_wrap(ctx_cls, "bindPip"); + fn_wrapper_1a_v<Context, decltype(&Context::unbindPip), &Context::unbindPip, conv_from_str<PipId>>::def_wrap( + ctx_cls, "unbindPip"); + fn_wrapper_1a<Context, decltype(&Context::checkPipAvail), &Context::checkPipAvail, pass_through<bool>, + conv_from_str<PipId>>::def_wrap(ctx_cls, "checkPipAvail"); + fn_wrapper_1a<Context, decltype(&Context::getBoundPipNet), &Context::getBoundPipNet, conv_to_str<IdString>, + conv_from_str<PipId>>::def_wrap(ctx_cls, "getBoundPipNet"); + fn_wrapper_1a<Context, decltype(&Context::getConflictingPipNet), &Context::getConflictingPipNet, + conv_to_str<IdString>, conv_from_str<PipId>>::def_wrap(ctx_cls, "getConflictingPipNet"); fn_wrapper_1a<Context, decltype(&Context::getPipsDownhill), &Context::getPipsDownhill, wrap_context<PipRange>, conv_from_str<WireId>>::def_wrap(ctx_cls, "getPipsDownhill"); diff --git a/ice40/arch_pybindings.h b/ice40/arch_pybindings.h index 7440e29d..e502905f 100644 --- a/ice40/arch_pybindings.h +++ b/ice40/arch_pybindings.h @@ -31,11 +31,7 @@ namespace PythonConversion { template <> struct string_converter<BelId> { - BelId from_str(Context *ctx, std::string name) - { - auto &&proxy = ctx->rproxy(); - return proxy.getBelByName(ctx->id(name)); - } + BelId from_str(Context *ctx, std::string name) { return ctx->getBelByName(ctx->id(name)); } std::string to_str(Context *ctx, BelId id) { @@ -54,22 +50,14 @@ template <> struct string_converter<BelType> template <> struct string_converter<WireId> { - WireId from_str(Context *ctx, std::string name) - { - auto &&proxy = ctx->rproxy(); - return proxy.getWireByName(ctx->id(name)); - } + WireId from_str(Context *ctx, std::string name) { return ctx->getWireByName(ctx->id(name)); } std::string to_str(Context *ctx, WireId id) { return ctx->getWireName(id).str(ctx); } }; template <> struct string_converter<PipId> { - PipId from_str(Context *ctx, std::string name) - { - auto &&proxy = ctx->rproxy(); - return proxy.getPipByName(ctx->id(name)); - } + PipId from_str(Context *ctx, std::string name) { return ctx->getPipByName(ctx->id(name)); } std::string to_str(Context *ctx, PipId id) { return ctx->getPipName(id).str(ctx); } }; diff --git a/ice40/bitstream.cc b/ice40/bitstream.cc index 87a96a22..a62c6c09 100644 --- a/ice40/bitstream.cc +++ b/ice40/bitstream.cc @@ -92,7 +92,6 @@ char get_hexdigit(int i) { return std::string("0123456789ABCDEF").at(i); } void write_asc(const Context *ctx, std::ostream &out) { - auto &&proxy = ctx->rproxy(); // [y][x][row][col] const ChipInfoPOD &ci = *ctx->chip_info; const BitstreamInfoPOD &bi = *ci.bits_info; @@ -129,7 +128,7 @@ void write_asc(const Context *ctx, std::ostream &out) } // Set pips for (auto pip : ctx->getPips()) { - if (proxy.getBoundPipNet(pip) != IdString()) { + if (ctx->pip_to_net[pip.index] != IdString()) { const PipInfoPOD &pi = ci.pip_data[pip.index]; const SwitchInfoPOD &swi = bi.switches[pi.switch_index]; for (int i = 0; i < swi.num_bits; i++) { @@ -200,8 +199,8 @@ void write_asc(const Context *ctx, std::ostream &out) NPNR_ASSERT(iez != -1); bool input_en = false; - if (!proxy.checkWireAvail(proxy.getWireBelPin(bel, PIN_D_IN_0)) || - !proxy.checkWireAvail(proxy.getWireBelPin(bel, PIN_D_IN_1))) { + if ((ctx->wire_to_net[ctx->getWireBelPin(bel, PIN_D_IN_0).index] != IdString()) || + (ctx->wire_to_net[ctx->getWireBelPin(bel, PIN_D_IN_1).index] != IdString())) { input_en = true; } @@ -272,7 +271,7 @@ void write_asc(const Context *ctx, std::ostream &out) } // Set config bits in unused IO and RAM for (auto bel : ctx->getBels()) { - if (proxy.checkBelAvail(bel) && ctx->getBelType(bel) == TYPE_SB_IO) { + if (ctx->bel_to_cell[bel.index] == IdString() && ctx->getBelType(bel) == TYPE_SB_IO) { const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_IO]; const BelInfoPOD &beli = ci.bel_data[bel.index]; int x = beli.x, y = beli.y, z = beli.z; @@ -285,7 +284,7 @@ void write_asc(const Context *ctx, std::ostream &out) set_config(ti, config.at(iey).at(iex), "IoCtrl.REN_" + std::to_string(iez), false); } } - } else if (proxy.checkBelAvail(bel) && ctx->getBelType(bel) == TYPE_ICESTORM_RAM) { + } else if (ctx->bel_to_cell[bel.index] == IdString() && ctx->getBelType(bel) == TYPE_ICESTORM_RAM) { const BelInfoPOD &beli = ci.bel_data[bel.index]; int x = beli.x, y = beli.y; const TileInfoPOD &ti = bi.tiles_nonrouting[TILE_RAMB]; @@ -432,7 +431,7 @@ void write_asc(const Context *ctx, std::ostream &out) // Write symbols // const bool write_symbols = 1; for (auto wire : ctx->getWires()) { - IdString net = proxy.getBoundWireNet(wire); + IdString net = ctx->getBoundWireNet(wire); if (net != IdString()) out << ".sym " << wire.index << " " << net.str(ctx) << std::endl; } diff --git a/ice40/main.cc b/ice40/main.cc index fdfe1f25..e77bdd34 100644 --- a/ice40/main.cc +++ b/ice40/main.cc @@ -51,8 +51,7 @@ void svg_dump_decal(const Context *ctx, const DecalXY &decal) const float scale = 10.0, offset = 10.0; const std::string style = "stroke=\"black\" stroke-width=\"0.1\" fill=\"none\""; - auto &&proxy = ctx->rproxy(); - for (auto &el : proxy.getDecalGraphics(decal.decal)) { + for (auto &el : ctx->getDecalGraphics(decal.decal)) { if (el.type == GraphicElement::G_BOX) { std::cout << "<rect x=\"" << (offset + scale * (decal.x + el.x1)) << "\" y=\"" << (offset + scale * (decal.y + el.y1)) << "\" height=\"" << (scale * (el.y2 - el.y1)) @@ -304,32 +303,31 @@ int main(int argc, char *argv[]) } if (vm.count("tmfuzz")) { - auto &&proxy = ctx->rproxy(); std::vector<WireId> src_wires, dst_wires; /*for (auto w : ctx->getWires()) src_wires.push_back(w);*/ for (auto b : ctx->getBels()) { if (ctx->getBelType(b) == TYPE_ICESTORM_LC) { - src_wires.push_back(proxy.getWireBelPin(b, PIN_O)); + src_wires.push_back(ctx->getWireBelPin(b, PIN_O)); } if (ctx->getBelType(b) == TYPE_SB_IO) { - src_wires.push_back(proxy.getWireBelPin(b, PIN_D_IN_0)); + src_wires.push_back(ctx->getWireBelPin(b, PIN_D_IN_0)); } } for (auto b : ctx->getBels()) { if (ctx->getBelType(b) == TYPE_ICESTORM_LC) { - dst_wires.push_back(proxy.getWireBelPin(b, PIN_I0)); - dst_wires.push_back(proxy.getWireBelPin(b, PIN_I1)); - dst_wires.push_back(proxy.getWireBelPin(b, PIN_I2)); - dst_wires.push_back(proxy.getWireBelPin(b, PIN_I3)); - dst_wires.push_back(proxy.getWireBelPin(b, PIN_CEN)); - dst_wires.push_back(proxy.getWireBelPin(b, PIN_CIN)); + dst_wires.push_back(ctx->getWireBelPin(b, PIN_I0)); + dst_wires.push_back(ctx->getWireBelPin(b, PIN_I1)); + dst_wires.push_back(ctx->getWireBelPin(b, PIN_I2)); + dst_wires.push_back(ctx->getWireBelPin(b, PIN_I3)); + dst_wires.push_back(ctx->getWireBelPin(b, PIN_CEN)); + dst_wires.push_back(ctx->getWireBelPin(b, PIN_CIN)); } if (ctx->getBelType(b) == TYPE_SB_IO) { - dst_wires.push_back(proxy.getWireBelPin(b, PIN_D_OUT_0)); - dst_wires.push_back(proxy.getWireBelPin(b, PIN_OUTPUT_ENABLE)); + dst_wires.push_back(ctx->getWireBelPin(b, PIN_D_OUT_0)); + dst_wires.push_back(ctx->getWireBelPin(b, PIN_OUTPUT_ENABLE)); } } diff --git a/ice40/place_legaliser.cc b/ice40/place_legaliser.cc index fcb47cfd..559358c7 100644 --- a/ice40/place_legaliser.cc +++ b/ice40/place_legaliser.cc @@ -119,17 +119,13 @@ class PlacementLegaliser bool legalise() { - log_info("Legalising logic cells...\n"); + log_info("Legalising design..\n"); init_logic_cells(); - log_info("Legalising carries...\n"); bool legalised_carries = legalise_carries(); if (!legalised_carries && !ctx->force) return false; - log_info("Legalising others...\n"); legalise_others(); - log_info("Legalising logic tiles...\n"); legalise_logic_tiles(); - log_info("Replacing cells...\n"); bool replaced_cells = replace_cells(); return legalised_carries && replaced_cells; } @@ -137,7 +133,6 @@ class PlacementLegaliser private: void init_logic_cells() { - auto &&proxy = ctx->rproxy(); for (auto bel : ctx->getBels()) { // Initialise the logic bels vector with unavailable invalid bels, dimensions [0..width][0..height[0..7] logic_bels.resize(ctx->chip_info->width + 1, @@ -148,7 +143,7 @@ class PlacementLegaliser // Using the non-standard API here to get (x, y, z) rather than just (x, y) auto bi = ctx->chip_info->bel_data[bel.index]; int x = bi.x, y = bi.y, z = bi.z; - IdString cell = proxy.getBoundBelCell(bel); + IdString cell = ctx->getBoundBelCell(bel); if (cell != IdString() && ctx->cells.at(cell)->belStrength >= STRENGTH_FIXED) logic_bels.at(x).at(y).at(z) = std::make_pair(bel, true); // locked out of use else @@ -200,33 +195,28 @@ class PlacementLegaliser } } bool success = true; - // Find midpoints for all chains, before we start tearing them up std::vector<CellChain> all_chains; - { - auto &&proxy = ctx->rproxy(); - for (auto &base_chain : carry_chains) { - if (ctx->verbose) { - log_info("Found carry chain: \n"); - for (auto entry : base_chain.cells) - log_info(" %s\n", entry->name.c_str(ctx)); - log_info("\n"); - } - std::vector<CellChain> split_chains = split_carry_chain(proxy, base_chain); - for (auto &chain : split_chains) { - get_chain_midpoint(ctx, chain, chain.mid_x, chain.mid_y); - all_chains.push_back(chain); - } + for (auto &base_chain : carry_chains) { + if (ctx->verbose) { + log_info("Found carry chain: \n"); + for (auto entry : base_chain.cells) + log_info(" %s\n", entry->name.c_str(ctx)); + log_info("\n"); + } + std::vector<CellChain> split_chains = split_carry_chain(base_chain); + for (auto &chain : split_chains) { + get_chain_midpoint(ctx, chain, chain.mid_x, chain.mid_y); + all_chains.push_back(chain); } } // Actual chain placement - auto &&proxy = ctx->rwproxy(); for (auto &chain : all_chains) { if (ctx->verbose) log_info("Placing carry chain starting at '%s'\n", chain.cells.front()->name.c_str(ctx)); float base_x = chain.mid_x, base_y = chain.mid_y - (chain.cells.size() / 16.0f); // Find Bel meeting requirements closest to the target base, returning location as <x, y, z> - auto chain_origin_bel = find_closest_bel(proxy, base_x, base_y, chain); + auto chain_origin_bel = find_closest_bel(base_x, base_y, chain); int place_x = std::get<0>(chain_origin_bel), place_y = std::get<1>(chain_origin_bel), place_z = std::get<2>(chain_origin_bel); if (place_x == -1) { @@ -243,7 +233,7 @@ class PlacementLegaliser // Place carry chain for (int i = 0; i < int(chain.cells.size()); i++) { int target_z = place_y * 8 + place_z + i; - place_lc(proxy, chain.cells.at(i), place_x, target_z / 8, target_z % 8); + place_lc(chain.cells.at(i), place_x, target_z / 8, target_z % 8); if (ctx->verbose) log_info(" Cell '%s' placed at (%d, %d, %d)\n", chain.cells.at(i)->name.c_str(ctx), place_x, target_z / 8, target_z % 8); @@ -253,7 +243,7 @@ class PlacementLegaliser } // Find Bel closest to a location, meeting chain requirements - std::tuple<int, int, int> find_closest_bel(MutateContext &proxy, float target_x, float target_y, CellChain &chain) + std::tuple<int, int, int> find_closest_bel(float target_x, float target_y, CellChain &chain) { std::tuple<int, int, int> best_origin = std::make_tuple(-1, -1, -1); wirelen_t best_wirelength = std::numeric_limits<wirelen_t>::max(); @@ -270,7 +260,7 @@ class PlacementLegaliser valid = false; break; } else { - wirelen += get_cell_wirelength_at_bel(proxy, ctx, chain.cells.at(k), lb.first); + wirelen += get_cell_wirelength_at_bel(ctx, chain.cells.at(k), lb.first); } } if (valid && wirelen < best_wirelength) { @@ -283,7 +273,7 @@ class PlacementLegaliser } // Split a carry chain into multiple legal chains - std::vector<CellChain> split_carry_chain(const ReadContext &proxy, CellChain &carryc) + std::vector<CellChain> split_carry_chain(CellChain &carryc) { bool start_of_chain = true; std::vector<CellChain> chains; @@ -308,7 +298,7 @@ class PlacementLegaliser } tile.push_back(cell); chains.back().cells.push_back(cell); - bool split_chain = (!proxy.logicCellsCompatible(tile)) || (int(chains.back().cells.size()) > max_length); + bool split_chain = (!ctx->logicCellsCompatible(tile)) || (int(chains.back().cells.size()) > max_length); if (split_chain) { CellInfo *passout = make_carry_pass_out(cell->ports.at(ctx->id("COUT"))); tile.pop_back(); @@ -335,22 +325,22 @@ class PlacementLegaliser } // Place a logic cell at a given grid location, handling rip-up etc - void place_lc(MutateContext &proxy, CellInfo *cell, int x, int y, int z) + void place_lc(CellInfo *cell, int x, int y, int z) { auto &loc = logic_bels.at(x).at(y).at(z); NPNR_ASSERT(!loc.second); BelId bel = loc.first; // Check if there is a cell presently at the location, which we will need to rip up - IdString existing = proxy.getBoundBelCell(bel); + IdString existing = ctx->getBoundBelCell(bel); if (existing != IdString()) { // TODO: keep track of the previous position of the ripped up cell, as a hint rippedCells.insert(existing); - proxy.unbindBel(bel); + ctx->unbindBel(bel); } if (cell->bel != BelId()) { - proxy.unbindBel(cell->bel); + ctx->unbindBel(cell->bel); } - proxy.bindBel(bel, cell->name, STRENGTH_LOCKED); + ctx->bindBel(bel, cell->name, STRENGTH_LOCKED); rippedCells.erase(cell->name); // If cell was ripped up previously, no need to re-place loc.second = true; // Bel is now unavailable for further use } @@ -433,20 +423,19 @@ class PlacementLegaliser // Legalise logic tiles void legalise_logic_tiles() { - auto &&proxy = ctx->rwproxy(); int width = ctx->chip_info->width, height = ctx->chip_info->height; for (int x = 1; x < width; x++) { for (int y = 1; y < height; y++) { BelId tileBel = logic_bels.at(x).at(y).at(0).first; if (tileBel != BelId()) { bool changed = true; - while (!proxy.isBelLocationValid(tileBel) && changed) { + while (!ctx->isBelLocationValid(tileBel) && changed) { changed = false; int max_score = 0; CellInfo *target = nullptr; for (int z = 0; z < 8; z++) { BelId bel = logic_bels.at(x).at(y).at(z).first; - IdString cell = proxy.getBoundBelCell(bel); + IdString cell = ctx->getBoundBelCell(bel); if (cell != IdString()) { CellInfo *ci = ctx->cells.at(cell).get(); if (ci->belStrength >= STRENGTH_STRONG) @@ -459,7 +448,7 @@ class PlacementLegaliser } } if (target != nullptr) { - proxy.unbindBel(target->bel); + ctx->unbindBel(target->bel); rippedCells.insert(target->name); changed = true; } @@ -472,14 +461,13 @@ class PlacementLegaliser // Legalise other tiles void legalise_others() { - auto &&proxy = ctx->rwproxy(); std::vector<CellInfo *> legalised_others; for (auto cell : sorted(ctx->cells)) { CellInfo *ci = cell.second; if (!is_lc(ctx, ci)) { if (ci->belStrength < STRENGTH_STRONG && ci->bel != BelId()) { - if (!proxy.isValidBelForCell(ci, ci->bel)) { - place_single_cell(proxy, ctx, ci, true); + if (!ctx->isValidBelForCell(ci, ci->bel)) { + place_single_cell(ctx, ci, true); } legalised_others.push_back(ci); } @@ -494,11 +482,10 @@ class PlacementLegaliser // Replace ripped-up cells bool replace_cells() { - auto &&proxy = ctx->rwproxy(); bool success = true; for (auto cell : sorted(rippedCells)) { CellInfo *ci = ctx->cells.at(cell).get(); - bool placed = place_single_cell(proxy, ctx, ci, true); + bool placed = place_single_cell(ctx, ci, true); if (!placed) { if (ctx->force) { log_warning("failed to place cell '%s' of type '%s'\n", cell.c_str(ctx), ci->type.c_str(ctx)); |