nextpnr/ice40/arch.h
David Shah b18ea204c2 Remove wire alias API
It has not actually been implemented in any router for over 2.5 years and causes nothing more than confusion. It can always be added back if it forms part of a future solution; possibly as part of a more general database structure rethink.

Signed-off-by: David Shah <dave@ds0.me>
2020-10-15 09:36:15 +01:00

897 lines
24 KiB
C++

/*
* nextpnr -- Next Generation Place and Route
*
* Copyright (C) 2018 Clifford Wolf <clifford@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
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
*/
#ifndef NEXTPNR_H
#error Include "arch.h" via "nextpnr.h" only.
#endif
NEXTPNR_NAMESPACE_BEGIN
/**** Everything in this section must be kept in sync with chipdb.py ****/
template <typename T> struct RelPtr
{
int32_t offset;
// void set(const T *ptr) {
// offset = reinterpret_cast<const char*>(ptr) -
// reinterpret_cast<const char*>(this);
// }
const T *get() const { return reinterpret_cast<const T *>(reinterpret_cast<const char *>(this) + offset); }
const T &operator[](size_t index) const { return get()[index]; }
const T &operator*() const { return *(get()); }
const T *operator->() const { return get(); }
};
NPNR_PACKED_STRUCT(struct BelWirePOD {
int32_t port;
int32_t type;
int32_t wire_index;
});
NPNR_PACKED_STRUCT(struct BelInfoPOD {
RelPtr<char> name;
int32_t type;
int32_t num_bel_wires;
RelPtr<BelWirePOD> bel_wires;
int8_t x, y, z;
int8_t padding_0;
});
NPNR_PACKED_STRUCT(struct BelPortPOD {
int32_t bel_index;
int32_t port;
});
NPNR_PACKED_STRUCT(struct PipInfoPOD {
enum PipFlags : uint32_t
{
FLAG_NONE = 0,
FLAG_ROUTETHRU = 1,
FLAG_NOCARRY = 2
};
// RelPtr<char> name;
int32_t src, dst;
int32_t fast_delay;
int32_t slow_delay;
int8_t x, y;
int16_t src_seg, dst_seg;
int16_t switch_mask;
int32_t switch_index;
PipFlags flags;
});
NPNR_PACKED_STRUCT(struct WireSegmentPOD {
int8_t x, y;
int16_t index;
});
NPNR_PACKED_STRUCT(struct WireInfoPOD {
enum WireType : int8_t
{
WIRE_TYPE_NONE = 0,
WIRE_TYPE_GLB2LOCAL = 1,
WIRE_TYPE_GLB_NETWK = 2,
WIRE_TYPE_LOCAL = 3,
WIRE_TYPE_LUTFF_IN = 4,
WIRE_TYPE_LUTFF_IN_LUT = 5,
WIRE_TYPE_LUTFF_LOUT = 6,
WIRE_TYPE_LUTFF_OUT = 7,
WIRE_TYPE_LUTFF_COUT = 8,
WIRE_TYPE_LUTFF_GLOBAL = 9,
WIRE_TYPE_CARRY_IN_MUX = 10,
WIRE_TYPE_SP4_V = 11,
WIRE_TYPE_SP4_H = 12,
WIRE_TYPE_SP12_V = 13,
WIRE_TYPE_SP12_H = 14
};
RelPtr<char> name;
int32_t num_uphill, num_downhill;
RelPtr<int32_t> pips_uphill, pips_downhill;
int32_t num_bel_pins;
RelPtr<BelPortPOD> bel_pins;
int32_t num_segments;
RelPtr<WireSegmentPOD> segments;
int32_t fast_delay;
int32_t slow_delay;
int8_t x, y, z;
WireType type;
});
NPNR_PACKED_STRUCT(struct PackagePinPOD {
RelPtr<char> name;
int32_t bel_index;
});
NPNR_PACKED_STRUCT(struct PackageInfoPOD {
RelPtr<char> name;
int32_t num_pins;
RelPtr<PackagePinPOD> pins;
});
enum TileType : uint32_t
{
TILE_NONE = 0,
TILE_LOGIC = 1,
TILE_IO = 2,
TILE_RAMB = 3,
TILE_RAMT = 4,
TILE_DSP0 = 5,
TILE_DSP1 = 6,
TILE_DSP2 = 7,
TILE_DSP3 = 8,
TILE_IPCON = 9
};
NPNR_PACKED_STRUCT(struct ConfigBitPOD { int8_t row, col; });
NPNR_PACKED_STRUCT(struct ConfigEntryPOD {
RelPtr<char> name;
int32_t num_bits;
RelPtr<ConfigBitPOD> bits;
});
NPNR_PACKED_STRUCT(struct TileInfoPOD {
int8_t cols, rows;
int16_t num_config_entries;
RelPtr<ConfigEntryPOD> entries;
});
static const int max_switch_bits = 5;
NPNR_PACKED_STRUCT(struct SwitchInfoPOD {
int32_t num_bits;
int32_t bel;
int8_t x, y;
ConfigBitPOD cbits[max_switch_bits];
});
NPNR_PACKED_STRUCT(struct IerenInfoPOD {
int8_t iox, ioy, ioz;
int8_t ierx, iery, ierz;
});
NPNR_PACKED_STRUCT(struct BitstreamInfoPOD {
int32_t num_switches, num_ierens;
RelPtr<TileInfoPOD> tiles_nonrouting;
RelPtr<SwitchInfoPOD> switches;
RelPtr<IerenInfoPOD> ierens;
});
NPNR_PACKED_STRUCT(struct BelConfigEntryPOD {
RelPtr<char> entry_name;
RelPtr<char> cbit_name;
int8_t x, y;
int16_t padding;
});
// Stores mapping between bel parameters and config bits,
// for extra cells where this mapping is non-trivial
NPNR_PACKED_STRUCT(struct BelConfigPOD {
int32_t bel_index;
int32_t num_entries;
RelPtr<BelConfigEntryPOD> entries;
});
NPNR_PACKED_STRUCT(struct CellPathDelayPOD {
int32_t from_port;
int32_t to_port;
int32_t fast_delay;
int32_t slow_delay;
});
NPNR_PACKED_STRUCT(struct CellTimingPOD {
int32_t type;
int32_t num_paths;
RelPtr<CellPathDelayPOD> path_delays;
});
NPNR_PACKED_STRUCT(struct GlobalNetworkInfoPOD {
uint8_t gb_x;
uint8_t gb_y;
uint8_t pi_gb_x;
uint8_t pi_gb_y;
uint8_t pi_gb_pio;
uint8_t pi_eb_bank;
uint16_t pi_eb_x;
uint16_t pi_eb_y;
uint16_t pad;
});
NPNR_PACKED_STRUCT(struct ChipInfoPOD {
int32_t width, height;
int32_t num_bels, num_wires, num_pips;
int32_t num_switches, num_belcfgs, num_packages;
int32_t num_timing_cells, num_global_networks;
RelPtr<BelInfoPOD> bel_data;
RelPtr<WireInfoPOD> wire_data;
RelPtr<PipInfoPOD> pip_data;
RelPtr<TileType> tile_grid;
RelPtr<BitstreamInfoPOD> bits_info;
RelPtr<BelConfigPOD> bel_config;
RelPtr<PackageInfoPOD> packages_data;
RelPtr<CellTimingPOD> cell_timing;
RelPtr<GlobalNetworkInfoPOD> global_network_info;
RelPtr<RelPtr<char>> tile_wire_names;
});
/************************ End of chipdb section. ************************/
struct BelIterator
{
int cursor;
BelIterator operator++()
{
cursor++;
return *this;
}
BelIterator operator++(int)
{
BelIterator prior(*this);
cursor++;
return prior;
}
bool operator!=(const BelIterator &other) const { return cursor != other.cursor; }
bool operator==(const BelIterator &other) const { return cursor == other.cursor; }
BelId operator*() const
{
BelId ret;
ret.index = cursor;
return ret;
}
};
struct BelRange
{
BelIterator b, e;
BelIterator begin() const { return b; }
BelIterator end() const { return e; }
};
// -----------------------------------------------------------------------
struct BelPinIterator
{
const BelPortPOD *ptr = nullptr;
void operator++() { ptr++; }
bool operator!=(const BelPinIterator &other) const { return ptr != other.ptr; }
BelPin operator*() const
{
BelPin ret;
ret.bel.index = ptr->bel_index;
ret.pin = ptr->port;
return ret;
}
};
struct BelPinRange
{
BelPinIterator b, e;
BelPinIterator begin() const { return b; }
BelPinIterator end() const { return e; }
};
// -----------------------------------------------------------------------
struct WireIterator
{
int cursor = -1;
void operator++() { cursor++; }
bool operator!=(const WireIterator &other) const { return cursor != other.cursor; }
WireId operator*() const
{
WireId ret;
ret.index = cursor;
return ret;
}
};
struct WireRange
{
WireIterator b, e;
WireIterator begin() const { return b; }
WireIterator end() const { return e; }
};
// -----------------------------------------------------------------------
struct AllPipIterator
{
int cursor = -1;
void operator++() { cursor++; }
bool operator!=(const AllPipIterator &other) const { return cursor != other.cursor; }
PipId operator*() const
{
PipId ret;
ret.index = cursor;
return ret;
}
};
struct AllPipRange
{
AllPipIterator b, e;
AllPipIterator begin() const { return b; }
AllPipIterator end() const { return e; }
};
// -----------------------------------------------------------------------
struct PipIterator
{
const int *cursor = nullptr;
void operator++() { cursor++; }
bool operator!=(const PipIterator &other) const { return cursor != other.cursor; }
PipId operator*() const
{
PipId ret;
ret.index = *cursor;
return ret;
}
};
struct PipRange
{
PipIterator b, e;
PipIterator begin() const { return b; }
PipIterator end() const { return e; }
};
struct ArchArgs
{
enum ArchArgsTypes
{
NONE,
LP384,
LP1K,
LP4K,
LP8K,
HX1K,
HX4K,
HX8K,
UP3K,
UP5K,
U1K,
U2K,
U4K
} type = NONE;
std::string package;
};
struct Arch : BaseCtx
{
bool fast_part;
const ChipInfoPOD *chip_info;
const PackageInfoPOD *package_info;
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;
mutable std::unordered_map<Loc, int> bel_by_loc;
std::vector<bool> bel_carry;
std::vector<CellInfo *> bel_to_cell;
std::vector<NetInfo *> wire_to_net;
std::vector<NetInfo *> pip_to_net;
std::vector<WireId> switches_locked;
ArchArgs args;
Arch(ArchArgs args);
static bool isAvailable(ArchArgs::ArchArgsTypes chip);
static std::vector<std::string> getSupportedPackages(ArchArgs::ArchArgsTypes chip);
std::string getChipName() const;
IdString archId() const { return id("ice40"); }
ArchArgs archArgs() const { return args; }
IdString archArgsToId(ArchArgs args) const;
// -------------------------------------------------
int getGridDimX() const { return chip_info->width; }
int getGridDimY() const { return chip_info->height; }
int getTileBelDimZ(int, int) const { return 8; }
int getTilePipDimZ(int, int) const { return 1; }
// -------------------------------------------------
BelId getBelByName(IdString name) const;
IdString getBelName(BelId bel) const
{
NPNR_ASSERT(bel != BelId());
return id(chip_info->bel_data[bel.index].name.get());
}
uint32_t getBelChecksum(BelId bel) const { return bel.index; }
void bindBel(BelId bel, CellInfo *cell, PlaceStrength strength)
{
NPNR_ASSERT(bel != BelId());
NPNR_ASSERT(bel_to_cell[bel.index] == nullptr);
bel_to_cell[bel.index] = cell;
bel_carry[bel.index] = (cell->type == id_ICESTORM_LC && cell->lcInfo.carryEnable);
cell->bel = bel;
cell->belStrength = strength;
refreshUiBel(bel);
}
void unbindBel(BelId bel)
{
NPNR_ASSERT(bel != BelId());
NPNR_ASSERT(bel_to_cell[bel.index] != nullptr);
bel_to_cell[bel.index]->bel = BelId();
bel_to_cell[bel.index]->belStrength = STRENGTH_NONE;
bel_to_cell[bel.index] = nullptr;
bel_carry[bel.index] = false;
refreshUiBel(bel);
}
bool checkBelAvail(BelId bel) const
{
NPNR_ASSERT(bel != BelId());
return bel_to_cell[bel.index] == nullptr;
}
CellInfo *getBoundBelCell(BelId bel) const
{
NPNR_ASSERT(bel != BelId());
return bel_to_cell[bel.index];
}
CellInfo *getConflictingBelCell(BelId bel) const
{
NPNR_ASSERT(bel != BelId());
return bel_to_cell[bel.index];
}
BelRange getBels() const
{
BelRange range;
range.b.cursor = 0;
range.e.cursor = chip_info->num_bels;
return range;
}
Loc getBelLocation(BelId bel) const
{
NPNR_ASSERT(bel != BelId());
Loc loc;
loc.x = chip_info->bel_data[bel.index].x;
loc.y = chip_info->bel_data[bel.index].y;
loc.z = chip_info->bel_data[bel.index].z;
return loc;
}
BelId getBelByLocation(Loc loc) const;
BelRange getBelsByTile(int x, int y) const;
bool getBelGlobalBuf(BelId bel) const { return chip_info->bel_data[bel.index].type == ID_SB_GB; }
IdString getBelType(BelId bel) const
{
NPNR_ASSERT(bel != BelId());
return IdString(chip_info->bel_data[bel.index].type);
}
std::vector<std::pair<IdString, std::string>> getBelAttrs(BelId bel) const;
WireId getBelPinWire(BelId bel, IdString pin) const;
PortType getBelPinType(BelId bel, IdString pin) const;
std::vector<IdString> getBelPins(BelId bel) const;
bool isBelLocked(BelId bel) const;
// -------------------------------------------------
WireId getWireByName(IdString name) const;
IdString getWireName(WireId wire) const
{
NPNR_ASSERT(wire != WireId());
return id(chip_info->wire_data[wire.index].name.get());
}
IdString getWireType(WireId wire) const;
std::vector<std::pair<IdString, std::string>> getWireAttrs(WireId wire) const;
uint32_t getWireChecksum(WireId wire) const { return wire.index; }
void bindWire(WireId wire, NetInfo *net, PlaceStrength strength)
{
NPNR_ASSERT(wire != WireId());
NPNR_ASSERT(wire_to_net[wire.index] == nullptr);
wire_to_net[wire.index] = net;
net->wires[wire].pip = PipId();
net->wires[wire].strength = strength;
refreshUiWire(wire);
}
void unbindWire(WireId wire)
{
NPNR_ASSERT(wire != WireId());
NPNR_ASSERT(wire_to_net[wire.index] != nullptr);
auto &net_wires = 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] = nullptr;
switches_locked[chip_info->pip_data[pip.index].switch_index] = WireId();
}
net_wires.erase(it);
wire_to_net[wire.index] = nullptr;
refreshUiWire(wire);
}
bool checkWireAvail(WireId wire) const
{
NPNR_ASSERT(wire != WireId());
return wire_to_net[wire.index] == nullptr;
}
NetInfo *getBoundWireNet(WireId wire) const
{
NPNR_ASSERT(wire != WireId());
return wire_to_net[wire.index];
}
WireId getConflictingWireWire(WireId wire) const { return wire; }
NetInfo *getConflictingWireNet(WireId wire) const
{
NPNR_ASSERT(wire != WireId());
return wire_to_net[wire.index];
}
DelayInfo getWireDelay(WireId wire) const
{
DelayInfo delay;
NPNR_ASSERT(wire != WireId());
if (fast_part)
delay.delay = chip_info->wire_data[wire.index].fast_delay;
else
delay.delay = chip_info->wire_data[wire.index].slow_delay;
return delay;
}
BelPinRange getWireBelPins(WireId wire) const
{
BelPinRange range;
NPNR_ASSERT(wire != WireId());
range.b.ptr = chip_info->wire_data[wire.index].bel_pins.get();
range.e.ptr = range.b.ptr + chip_info->wire_data[wire.index].num_bel_pins;
return range;
}
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, NetInfo *net, PlaceStrength strength)
{
NPNR_ASSERT(pip != PipId());
NPNR_ASSERT(pip_to_net[pip.index] == nullptr);
NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] == WireId());
WireId dst;
dst.index = chip_info->pip_data[pip.index].dst;
NPNR_ASSERT(wire_to_net[dst.index] == nullptr);
pip_to_net[pip.index] = net;
switches_locked[chip_info->pip_data[pip.index].switch_index] = dst;
wire_to_net[dst.index] = net;
net->wires[dst].pip = pip;
net->wires[dst].strength = strength;
refreshUiPip(pip);
refreshUiWire(dst);
}
void unbindPip(PipId pip)
{
NPNR_ASSERT(pip != PipId());
NPNR_ASSERT(pip_to_net[pip.index] != nullptr);
NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] != WireId());
WireId dst;
dst.index = chip_info->pip_data[pip.index].dst;
NPNR_ASSERT(wire_to_net[dst.index] != nullptr);
wire_to_net[dst.index] = nullptr;
pip_to_net[pip.index]->wires.erase(dst);
pip_to_net[pip.index] = nullptr;
switches_locked[chip_info->pip_data[pip.index].switch_index] = WireId();
refreshUiPip(pip);
refreshUiWire(dst);
}
bool ice40_pip_hard_unavail(PipId pip) const
{
NPNR_ASSERT(pip != PipId());
auto &pi = chip_info->pip_data[pip.index];
auto &si = chip_info->bits_info->switches[pi.switch_index];
if (pi.flags & PipInfoPOD::FLAG_ROUTETHRU) {
NPNR_ASSERT(si.bel >= 0);
if (bel_to_cell[si.bel] != nullptr)
return true;
}
if (pi.flags & PipInfoPOD::FLAG_NOCARRY) {
NPNR_ASSERT(si.bel >= 0);
if (bel_carry[si.bel])
return true;
}
return false;
}
bool checkPipAvail(PipId pip) const
{
if (ice40_pip_hard_unavail(pip))
return false;
auto &pi = chip_info->pip_data[pip.index];
return switches_locked[pi.switch_index] == WireId();
}
NetInfo *getBoundPipNet(PipId pip) const
{
NPNR_ASSERT(pip != PipId());
return pip_to_net[pip.index];
}
WireId getConflictingPipWire(PipId pip) const
{
if (ice40_pip_hard_unavail(pip))
return WireId();
return switches_locked[chip_info->pip_data[pip.index].switch_index];
}
NetInfo *getConflictingPipNet(PipId pip) const
{
if (ice40_pip_hard_unavail(pip))
return nullptr;
WireId wire = switches_locked[chip_info->pip_data[pip.index].switch_index];
return wire == WireId() ? nullptr : wire_to_net[wire.index];
}
AllPipRange getPips() const
{
AllPipRange range;
range.b.cursor = 0;
range.e.cursor = chip_info->num_pips;
return range;
}
Loc getPipLocation(PipId pip) const
{
Loc loc;
loc.x = chip_info->pip_data[pip.index].x;
loc.y = chip_info->pip_data[pip.index].y;
loc.z = 0;
return loc;
}
IdString getPipName(PipId pip) const;
IdString getPipType(PipId pip) const;
std::vector<std::pair<IdString, std::string>> getPipAttrs(PipId pip) const;
uint32_t getPipChecksum(PipId pip) const { return pip.index; }
WireId getPipSrcWire(PipId pip) const
{
WireId wire;
NPNR_ASSERT(pip != PipId());
wire.index = chip_info->pip_data[pip.index].src;
return wire;
}
WireId getPipDstWire(PipId pip) const
{
WireId wire;
NPNR_ASSERT(pip != PipId());
wire.index = chip_info->pip_data[pip.index].dst;
return wire;
}
DelayInfo getPipDelay(PipId pip) const
{
DelayInfo delay;
NPNR_ASSERT(pip != PipId());
if (fast_part)
delay.delay = chip_info->pip_data[pip.index].fast_delay;
else
delay.delay = chip_info->pip_data[pip.index].slow_delay;
return delay;
}
PipRange getPipsDownhill(WireId wire) const
{
PipRange range;
NPNR_ASSERT(wire != WireId());
range.b.cursor = chip_info->wire_data[wire.index].pips_downhill.get();
range.e.cursor = range.b.cursor + chip_info->wire_data[wire.index].num_downhill;
return range;
}
PipRange getPipsUphill(WireId wire) const
{
PipRange range;
NPNR_ASSERT(wire != WireId());
range.b.cursor = chip_info->wire_data[wire.index].pips_uphill.get();
range.e.cursor = range.b.cursor + chip_info->wire_data[wire.index].num_uphill;
return range;
}
BelId getPackagePinBel(const std::string &pin) const;
std::string getBelPackagePin(BelId bel) const;
// -------------------------------------------------
GroupId getGroupByName(IdString name) const;
IdString getGroupName(GroupId group) const;
std::vector<GroupId> getGroups() const;
std::vector<BelId> getGroupBels(GroupId group) const;
std::vector<WireId> getGroupWires(GroupId group) const;
std::vector<PipId> getGroupPips(GroupId group) const;
std::vector<GroupId> getGroupGroups(GroupId group) const;
// -------------------------------------------------
delay_t estimateDelay(WireId src, WireId dst) const;
delay_t predictDelay(const NetInfo *net_info, const PortRef &sink) const;
delay_t getDelayEpsilon() const { return 20; }
delay_t getRipupDelayPenalty() const { return 200; }
float getDelayNS(delay_t v) const { return v * 0.001; }
DelayInfo getDelayFromNS(float ns) const
{
DelayInfo del;
del.delay = delay_t(ns * 1000);
return del;
}
uint32_t getDelayChecksum(delay_t v) const { return v; }
bool getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const;
ArcBounds getRouteBoundingBox(WireId src, WireId dst) const;
// -------------------------------------------------
bool pack();
bool place();
bool route();
// -------------------------------------------------
std::vector<GraphicElement> getDecalGraphics(DecalId decal) const;
DecalXY getBelDecal(BelId bel) const;
DecalXY getWireDecal(WireId wire) const;
DecalXY getPipDecal(PipId pip) const;
DecalXY getGroupDecal(GroupId group) const;
// -------------------------------------------------
// Get the delay through a cell from one port to another, returning false
// if no path exists. This only considers combinational delays, as required by the Arch API
bool getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const;
// getCellDelayInternal is similar to the above, but without false path checks and including clock to out delays
// for internal arch use only
bool getCellDelayInternal(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const;
// Get the port class, also setting clockInfoCount to the number of TimingClockingInfos associated with a port
TimingPortClass getPortTimingClass(const CellInfo *cell, IdString port, int &clockInfoCount) const;
// Get the TimingClockingInfo of a port
TimingClockingInfo getPortClockingInfo(const CellInfo *cell, IdString port, int index) const;
// Return true if a port is a net
bool isGlobalNet(const NetInfo *net) const;
// -------------------------------------------------
// 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 CellInfo **it, const size_t size) const;
// -------------------------------------------------
// Assign architecure-specific arguments to nets and cells, which must be
// called between packing or further
// netlist modifications, and validity checks
void assignArchInfo();
void assignCellInfo(CellInfo *cell);
// -------------------------------------------------
BelPin getIOBSharingPLLPin(BelId pll, IdString pll_pin) const
{
auto wire = getBelPinWire(pll, pll_pin);
for (auto src_bel : getWireBelPins(wire)) {
if (getBelType(src_bel.bel) == id_SB_IO && src_bel.pin == id_D_IN_0) {
return src_bel;
}
}
NPNR_ASSERT_FALSE("Expected PLL pin to share an output with an SB_IO D_IN_{0,1}");
}
int getDrivenGlobalNetwork(BelId bel) const
{
NPNR_ASSERT(getBelType(bel) == id_SB_GB);
IdString glb_net = getWireName(getBelPinWire(bel, id_GLOBAL_BUFFER_OUTPUT));
return std::stoi(std::string("") + glb_net.str(this).back());
}
static const std::string defaultPlacer;
static const std::vector<std::string> availablePlacers;
static const std::string defaultRouter;
static const std::vector<std::string> availableRouters;
};
void ice40DelayFuzzerMain(Context *ctx);
NEXTPNR_NAMESPACE_END