Merge pull request #636 from litghost/add_pseudo_pip_data
Add pseudo pip data
This commit is contained in:
commit
53ed6979a9
2
.github/ci/build_interchange.sh
vendored
2
.github/ci/build_interchange.sh
vendored
@ -26,7 +26,7 @@ popd
|
||||
RAPIDWRIGHT_PATH="`pwd`/RapidWright"
|
||||
INTERCHANGE_SCHEMA_PATH="`pwd`/3rdparty/fpga-interchange-schema/interchange"
|
||||
PYTHON_INTERCHANGE_PATH="`pwd`/python-fpga-interchange"
|
||||
PYTHON_INTERCHANGE_TAG="v0.0.1"
|
||||
PYTHON_INTERCHANGE_TAG="v0.0.2"
|
||||
|
||||
# Install python-fpga-interchange libraries
|
||||
git clone -b $PYTHON_INTERCHANGE_TAG https://github.com/SymbiFlow/python-fpga-interchange.git $PYTHON_INTERCHANGE_PATH
|
||||
|
@ -747,6 +747,40 @@ bool Arch::route_vcc_to_unused_lut_pins()
|
||||
{
|
||||
std::string router = str_or_default(settings, id("router"), defaultRouter);
|
||||
|
||||
HashTables::HashMap<WireId, const NetInfo *> bound_wires;
|
||||
for (auto &net_pair : nets) {
|
||||
const NetInfo *net = net_pair.second.get();
|
||||
for (auto &wire_pair : net->wires) {
|
||||
auto result = bound_wires.emplace(wire_pair.first, net);
|
||||
NPNR_ASSERT(result.first->second == net);
|
||||
|
||||
PipId pip = wire_pair.second.pip;
|
||||
if (pip == PipId()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const PipInfoPOD &pip_data = pip_info(chip_info, pip);
|
||||
#ifdef DEBUG_LUT_MAPPING
|
||||
if (getCtx()->verbose) {
|
||||
log_info("Pip %s in use, has %zu pseudo wires!\n", nameOfPip(pip), pip_data.pseudo_cell_wires.size());
|
||||
}
|
||||
#endif
|
||||
|
||||
WireId wire;
|
||||
wire.tile = pip.tile;
|
||||
for (int32_t wire_index : pip_data.pseudo_cell_wires) {
|
||||
wire.index = wire_index;
|
||||
#ifdef DEBUG_LUT_MAPPING
|
||||
if (getCtx()->verbose) {
|
||||
log_info("Marking wire %s as in use due to pseudo pip\n", nameOfWire(wire));
|
||||
}
|
||||
#endif
|
||||
auto result = bound_wires.emplace(wire, net);
|
||||
NPNR_ASSERT(result.first->second == net);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fixup LUT vcc pins.
|
||||
IdString vcc_net_name(chip_info->constants->vcc_net_name);
|
||||
for (BelId bel : getBels()) {
|
||||
@ -766,14 +800,22 @@ bool Arch::route_vcc_to_unused_lut_pins()
|
||||
port_info.net = nullptr;
|
||||
|
||||
WireId lut_pin_wire = getBelPinWire(bel, bel_pin);
|
||||
auto iter = wire_to_net.find(lut_pin_wire);
|
||||
if (iter != wire_to_net.end()) {
|
||||
if (iter->second != nullptr) {
|
||||
// This pin is now used by a route through.
|
||||
continue;
|
||||
auto iter = bound_wires.find(lut_pin_wire);
|
||||
if (iter != bound_wires.end()) {
|
||||
#ifdef DEBUG_LUT_MAPPING
|
||||
if (getCtx()->verbose) {
|
||||
log_info("%s is now used as a LUT route-through, not tying to VCC\n", nameOfWire(lut_pin_wire));
|
||||
}
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_LUT_MAPPING
|
||||
if (getCtx()->verbose) {
|
||||
log_info("%s is an unused LUT pin, tying to VCC\n", nameOfWire(lut_pin_wire));
|
||||
}
|
||||
#endif
|
||||
|
||||
auto result = cell->ports.emplace(bel_pin, port_info);
|
||||
if (result.second) {
|
||||
cell->cell_bel_pins[bel_pin].push_back(bel_pin);
|
||||
@ -1351,6 +1393,55 @@ void Arch::decode_lut_cells()
|
||||
}
|
||||
}
|
||||
|
||||
void Arch::remove_pip_pseudo_wires(PipId pip, NetInfo *net)
|
||||
{
|
||||
WireId wire;
|
||||
wire.tile = pip.tile;
|
||||
const PipInfoPOD &pip_data = pip_info(chip_info, pip);
|
||||
for (int32_t wire_index : pip_data.pseudo_cell_wires) {
|
||||
NPNR_ASSERT(wire_index != -1);
|
||||
wire.index = wire_index;
|
||||
|
||||
auto iter = wire_to_net.find(wire);
|
||||
NPNR_ASSERT(iter != wire_to_net.end());
|
||||
// This wire better already have been assigned to this net!
|
||||
if (iter->second != net) {
|
||||
if (iter->second == nullptr) {
|
||||
log_error("Wire %s part of pseudo pip %s but net is null\n", nameOfWire(wire), nameOfPip(pip));
|
||||
} else {
|
||||
log_error("Wire %s part of pseudo pip %s but net is '%s' instead of net '%s'\n", nameOfWire(wire),
|
||||
nameOfPip(pip), iter->second->name.c_str(this), net->name.c_str(this));
|
||||
}
|
||||
}
|
||||
|
||||
auto wire_iter = net->wires.find(wire);
|
||||
if (wire_iter != net->wires.end()) {
|
||||
#ifdef DEBUG_BINDING
|
||||
if (getCtx()->verbose) {
|
||||
log_info("Removing %s from net %s, but it's in net wires\n", nameOfWire(wire), net->name.c_str(this));
|
||||
}
|
||||
#endif
|
||||
// This wire is part of net->wires, make sure it has no pip,
|
||||
// but leave it alone. It will get cleaned up via
|
||||
// unbindWire.
|
||||
if (wire_iter->second.pip != PipId() && wire_iter->second.pip != pip) {
|
||||
log_error("Wire %s report source'd from pip %s, which is not %s\n", nameOfWire(wire),
|
||||
nameOfPip(wire_iter->second.pip), nameOfPip(pip));
|
||||
}
|
||||
NPNR_ASSERT(wire_iter->second.pip == PipId() || wire_iter->second.pip == pip);
|
||||
} else {
|
||||
// This wire is not in net->wires, update wire_to_net.
|
||||
#ifdef DEBUG_BINDING
|
||||
if (getCtx()->verbose) {
|
||||
log_info("Removing %s from net %s in remove_pip_pseudo_wires\n", nameOfWire(wire),
|
||||
net->name.c_str(this));
|
||||
}
|
||||
#endif
|
||||
iter->second = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Arch::assign_net_to_wire(WireId wire, NetInfo *net, const char *src, bool require_empty)
|
||||
{
|
||||
#ifdef DEBUG_BINDING
|
||||
@ -1402,6 +1493,7 @@ void Arch::unassign_wire(WireId wire)
|
||||
NPNR_ASSERT(pip_iter != pip_to_net.end());
|
||||
NPNR_ASSERT(pip_iter->second == net);
|
||||
pip_iter->second = nullptr;
|
||||
remove_pip_pseudo_wires(pip, net);
|
||||
}
|
||||
|
||||
net_wires.erase(it);
|
||||
@ -1430,6 +1522,9 @@ void Arch::unbindPip(PipId pip)
|
||||
WireId dst = getPipDstWire(pip);
|
||||
auto wire_iter = wire_to_net.find(dst);
|
||||
NPNR_ASSERT(wire_iter != wire_to_net.end());
|
||||
NPNR_ASSERT(wire_iter->second == net);
|
||||
|
||||
remove_pip_pseudo_wires(pip, net);
|
||||
|
||||
// Clear the net now.
|
||||
pip_iter->second = nullptr;
|
||||
@ -1466,6 +1561,7 @@ void Arch::bindPip(PipId pip, NetInfo *net, PlaceStrength strength)
|
||||
}
|
||||
|
||||
assign_net_to_wire(dst, net, "bindPip", /*require_empty=*/true);
|
||||
assign_pip_pseudo_wires(pip, net);
|
||||
|
||||
{
|
||||
auto result = net->wires.emplace(dst, PipMap{pip, strength});
|
||||
@ -1516,6 +1612,7 @@ bool Arch::check_pip_avail_for_net(PipId pip, NetInfo *net) const
|
||||
}
|
||||
}
|
||||
|
||||
WireId src = getPipSrcWire(pip);
|
||||
WireId dst = getPipDstWire(pip);
|
||||
|
||||
auto wire_iter = wire_to_net.find(dst);
|
||||
@ -1550,7 +1647,28 @@ bool Arch::check_pip_avail_for_net(PipId pip, NetInfo *net) const
|
||||
}
|
||||
}
|
||||
|
||||
// If this pip is a route-though, make sure all of the route-though
|
||||
// wires are unbound.
|
||||
const PipInfoPOD &pip_data = pip_info(chip_info, pip);
|
||||
WireId wire;
|
||||
wire.tile = pip.tile;
|
||||
for (int32_t wire_index : pip_data.pseudo_cell_wires) {
|
||||
wire.index = wire_index;
|
||||
NPNR_ASSERT(src != wire);
|
||||
NPNR_ASSERT(dst != wire);
|
||||
|
||||
NetInfo *net = getConflictingWireNet(wire);
|
||||
if (net != nullptr) {
|
||||
#ifdef DEBUG_BINDING
|
||||
if (getCtx()->verbose) {
|
||||
log_info("Pip %s is not available because wire %s is tied to net %s\n", getCtx()->nameOfPip(pip),
|
||||
getCtx()->nameOfWire(wire), net->name.c_str(getCtx()));
|
||||
}
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (pip_data.site != -1 && net != nullptr) {
|
||||
NPNR_ASSERT(net->driver.cell != nullptr);
|
||||
NPNR_ASSERT(net->driver.cell->bel != BelId());
|
||||
@ -1600,6 +1718,10 @@ bool Arch::check_pip_avail_for_net(PipId pip, NetInfo *net) const
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: This pseudo pip check is incomplete, because constraint
|
||||
// failures will not be detected. However the current FPGA
|
||||
// interchange schema does not provide a cell type to place.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -515,6 +515,20 @@ struct Arch : ArchAPI<ArchRanges>
|
||||
|
||||
void assign_net_to_wire(WireId wire, NetInfo *net, const char *src, bool require_empty);
|
||||
|
||||
void assign_pip_pseudo_wires(PipId pip, NetInfo *net)
|
||||
{
|
||||
NPNR_ASSERT(net != nullptr);
|
||||
WireId wire;
|
||||
wire.tile = pip.tile;
|
||||
const PipInfoPOD &pip_data = pip_info(chip_info, pip);
|
||||
for (int32_t wire_index : pip_data.pseudo_cell_wires) {
|
||||
wire.index = wire_index;
|
||||
assign_net_to_wire(wire, net, "pseudo", /*require_empty=*/true);
|
||||
}
|
||||
}
|
||||
|
||||
void remove_pip_pseudo_wires(PipId pip, NetInfo *net);
|
||||
|
||||
void unassign_wire(WireId wire);
|
||||
|
||||
void bindPip(PipId pip, NetInfo *net, PlaceStrength strength) final;
|
||||
|
@ -34,7 +34,7 @@ NEXTPNR_NAMESPACE_BEGIN
|
||||
* kExpectedChipInfoVersion
|
||||
*/
|
||||
|
||||
static constexpr int32_t kExpectedChipInfoVersion = 1;
|
||||
static constexpr int32_t kExpectedChipInfoVersion = 2;
|
||||
|
||||
// Flattened site indexing.
|
||||
//
|
||||
@ -110,6 +110,7 @@ NPNR_PACKED_STRUCT(struct PipInfoPOD {
|
||||
int16_t site_variant; // site variant index in tile
|
||||
int16_t bel; // BEL this pip belongs to if site pip.
|
||||
int16_t extra_data;
|
||||
RelSlice<int32_t> pseudo_cell_wires;
|
||||
});
|
||||
|
||||
NPNR_PACKED_STRUCT(struct ConstraintTagPOD {
|
||||
|
Loading…
Reference in New Issue
Block a user