aboutsummaryrefslogtreecommitdiffstats
path: root/fpga_interchange/arch.cc
diff options
context:
space:
mode:
authorKeith Rothman <537074+litghost@users.noreply.github.com>2021-02-23 13:35:45 -0800
committerKeith Rothman <537074+litghost@users.noreply.github.com>2021-02-23 14:09:28 -0800
commita30043c8da1b1cc46a2dcfb90aa3a06d4f4ed4e9 (patch)
tree7d9558216c7b9858bd31323ff3482b50e9d5c05f /fpga_interchange/arch.cc
parent184665652eaf351bf9337b524c5d82a50ce54041 (diff)
downloadnextpnr-a30043c8da1b1cc46a2dcfb90aa3a06d4f4ed4e9.tar.gz
nextpnr-a30043c8da1b1cc46a2dcfb90aa3a06d4f4ed4e9.tar.bz2
nextpnr-a30043c8da1b1cc46a2dcfb90aa3a06d4f4ed4e9.zip
Fix assorted bugs in FPGA interchange.
Fixes: - Only use map constant pins during routing, and not during placement. - Unmapped cell ports have no BEL pins. - Fix SiteRouter congestion not taking into account initial expansion. - Fix psuedo-site pip output. Signed-off-by: Keith Rothman <537074+litghost@users.noreply.github.com>
Diffstat (limited to 'fpga_interchange/arch.cc')
-rw-r--r--fpga_interchange/arch.cc243
1 files changed, 158 insertions, 85 deletions
diff --git a/fpga_interchange/arch.cc b/fpga_interchange/arch.cc
index 776fbdb0..dc99f1cd 100644
--- a/fpga_interchange/arch.cc
+++ b/fpga_interchange/arch.cc
@@ -195,10 +195,7 @@ Arch::Arch(ArchArgs args) : args(args)
default_tags.resize(max_tag_count);
}
-
-void Arch::init() {
- dedicated_interconnect.init(getCtx());
-}
+void Arch::init() { dedicated_interconnect.init(getCtx()); }
// -----------------------------------------------------------------------
@@ -615,6 +612,14 @@ bool Arch::place()
{
std::string placer = str_or_default(settings, id("placer"), defaultPlacer);
+ // Re-map BEL pins without constant pins
+ for (BelId bel : getBels()) {
+ CellInfo *cell = getBoundBelCell(bel);
+ if (cell != nullptr && cell->cell_mapping != -1) {
+ map_cell_pins(cell, cell->cell_mapping, /*bind_constants=*/false);
+ }
+ }
+
if (placer == "heap") {
PlacerHeapCfg cfg(getCtx());
cfg.criticalityExponent = 7;
@@ -644,6 +649,14 @@ bool Arch::route()
{
std::string router = str_or_default(settings, id("router"), defaultRouter);
+ // Re-map BEL pins with constant pins
+ for (BelId bel : getBels()) {
+ CellInfo *cell = getBoundBelCell(bel);
+ if (cell != nullptr && cell->cell_mapping != -1) {
+ map_cell_pins(cell, cell->cell_mapping, /*bind_constants=*/true);
+ }
+ }
+
bool result;
if (router == "router1") {
result = router1(getCtx(), Router1Cfg(getCtx()));
@@ -683,13 +696,33 @@ DecalXY Arch::getGroupDecal(GroupId pip) const { return {}; };
delay_t Arch::estimateDelay(WireId src, WireId dst) const
{
// FIXME: Implement something to push the A* router in the right direction.
- return 0;
+ int src_x, src_y;
+ get_tile_x_y(src.tile, &src_x, &src_y);
+
+ int dst_x, dst_y;
+ get_tile_x_y(dst.tile, &dst_x, &dst_y);
+
+ delay_t base = 30 * std::min(std::abs(dst_x - src_x), 18) + 10 * std::max(std::abs(dst_x - src_x) - 18, 0) +
+ 60 * std::min(std::abs(dst_y - src_y), 6) + 20 * std::max(std::abs(dst_y - src_y) - 6, 0) + 300;
+
+ base = (base * 3) / 2;
+ return base;
}
delay_t Arch::predictDelay(const NetInfo *net_info, const PortRef &sink) const
{
// FIXME: Implement when adding timing-driven place and route.
- return 0;
+ int src_x, src_y;
+ get_tile_x_y(net_info->driver.cell->bel.tile, &src_x, &src_y);
+
+ int dst_x, dst_y;
+ get_tile_x_y(sink.cell->bel.tile, &dst_x, &dst_y);
+
+ delay_t base = 30 * std::min(std::abs(dst_x - src_x), 18) + 10 * std::max(std::abs(dst_x - src_x) - 18, 0) +
+ 60 * std::min(std::abs(dst_y - src_y), 6) + 20 * std::max(std::abs(dst_y - src_y) - 6, 0) + 300;
+
+ base = (base * 3) / 2;
+ return base;
}
bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayQuad &delay) const
@@ -755,57 +788,64 @@ const std::vector<std::string> Arch::availablePlacers = {"sa",
const std::string Arch::defaultRouter = "router2";
const std::vector<std::string> Arch::availableRouters = {"router1", "router2"};
-void Arch::map_cell_pins(CellInfo *cell, int32_t mapping)
+void Arch::map_cell_pins(CellInfo *cell, int32_t mapping, bool bind_constants)
{
cell->cell_mapping = mapping;
cell->cell_bel_pins.clear();
+ for (IdString const_port : cell->const_ports) {
+ NPNR_ASSERT(cell->ports.erase(const_port));
+ }
const CellBelMapPOD &cell_pin_map = chip_info->cell_map->cell_bel_map[mapping];
+ IdString gnd_net_name(chip_info->constants->gnd_net_name);
+ IdString vcc_net_name(chip_info->constants->vcc_net_name);
+
for (const auto &pin_map : cell_pin_map.common_pins) {
IdString cell_pin(pin_map.cell_pin);
IdString bel_pin(pin_map.bel_pin);
if (cell_pin.str(this) == "GND") {
- IdString gnd_net_name(chip_info->constants->gnd_net_name);
-
- PortInfo port_info;
- port_info.name = bel_pin;
- port_info.type = PORT_IN;
- port_info.net = nullptr;
+ if (bind_constants) {
+ PortInfo port_info;
+ port_info.name = bel_pin;
+ port_info.type = PORT_IN;
+ port_info.net = nullptr;
- auto result = cell->ports.emplace(bel_pin, port_info);
- if(result.second) {
- cell->cell_bel_pins[bel_pin].push_back(bel_pin);
- connectPort(gnd_net_name, cell->name, bel_pin);
- } else {
- NPNR_ASSERT(result.first->second.net == getNetByAlias(gnd_net_name));
- auto result2 = cell->cell_bel_pins.emplace(bel_pin, std::vector<IdString>({bel_pin}));
- NPNR_ASSERT(result2.first->second.at(0) == bel_pin);
- NPNR_ASSERT(result2.first->second.size() == 1);
+ auto result = cell->ports.emplace(bel_pin, port_info);
+ if (result.second) {
+ cell->cell_bel_pins[bel_pin].push_back(bel_pin);
+ connectPort(gnd_net_name, cell->name, bel_pin);
+ cell->const_ports.emplace(bel_pin);
+ } else {
+ NPNR_ASSERT(result.first->second.net == getNetByAlias(gnd_net_name));
+ auto result2 = cell->cell_bel_pins.emplace(bel_pin, std::vector<IdString>({bel_pin}));
+ NPNR_ASSERT(result2.first->second.at(0) == bel_pin);
+ NPNR_ASSERT(result2.first->second.size() == 1);
+ }
}
continue;
}
if (cell_pin.str(this) == "VCC") {
- IdString vcc_net_name(chip_info->constants->vcc_net_name);
-
- PortInfo port_info;
- port_info.name = bel_pin;
- port_info.type = PORT_IN;
- port_info.net = nullptr;
+ if (bind_constants) {
+ PortInfo port_info;
+ port_info.name = bel_pin;
+ port_info.type = PORT_IN;
+ port_info.net = nullptr;
- auto result = cell->ports.emplace(bel_pin, port_info);
- if(result.second) {
- cell->cell_bel_pins[bel_pin].push_back(bel_pin);
- connectPort(vcc_net_name, cell->name, bel_pin);
- } else {
- NPNR_ASSERT(result.first->second.net == getNetByAlias(vcc_net_name));
- auto result2 = cell->cell_bel_pins.emplace(bel_pin, std::vector<IdString>({bel_pin}));
- NPNR_ASSERT(result2.first->second.at(0) == bel_pin);
- NPNR_ASSERT(result2.first->second.size() == 1);
+ auto result = cell->ports.emplace(bel_pin, port_info);
+ if (result.second) {
+ cell->cell_bel_pins[bel_pin].push_back(bel_pin);
+ connectPort(vcc_net_name, cell->name, bel_pin);
+ cell->const_ports.emplace(bel_pin);
+ } else {
+ NPNR_ASSERT(result.first->second.net == getNetByAlias(vcc_net_name));
+ auto result2 = cell->cell_bel_pins.emplace(bel_pin, std::vector<IdString>({bel_pin}));
+ NPNR_ASSERT(result2.first->second.at(0) == bel_pin);
+ NPNR_ASSERT(result2.first->second.size() == 1);
+ }
}
-
continue;
}
@@ -830,30 +870,44 @@ void Arch::map_cell_pins(CellInfo *cell, int32_t mapping)
IdString bel_pin(pin_map.bel_pin);
if (cell_pin.str(this) == "GND") {
- PortInfo port_info;
- port_info.name = bel_pin;
- port_info.type = PORT_IN;
-
- auto result = cell->ports.emplace(bel_pin, port_info);
- NPNR_ASSERT(result.second);
-
- cell->cell_bel_pins[bel_pin].push_back(bel_pin);
-
- connectPort(IdString(chip_info->constants->gnd_net_name), cell->name, bel_pin);
+ if (bind_constants) {
+ PortInfo port_info;
+ port_info.name = bel_pin;
+ port_info.type = PORT_IN;
+
+ auto result = cell->ports.emplace(bel_pin, port_info);
+ if (result.second) {
+ cell->cell_bel_pins[bel_pin].push_back(bel_pin);
+ connectPort(gnd_net_name, cell->name, bel_pin);
+ cell->const_ports.emplace(bel_pin);
+ } else {
+ NPNR_ASSERT(result.first->second.net == getNetByAlias(gnd_net_name));
+ auto result2 = cell->cell_bel_pins.emplace(bel_pin, std::vector<IdString>({bel_pin}));
+ NPNR_ASSERT(result2.first->second.at(0) == bel_pin);
+ NPNR_ASSERT(result2.first->second.size() == 1);
+ }
+ }
continue;
}
if (cell_pin.str(this) == "VCC") {
- PortInfo port_info;
- port_info.name = bel_pin;
- port_info.type = PORT_IN;
-
- auto result = cell->ports.emplace(bel_pin, port_info);
- NPNR_ASSERT(result.second);
-
- cell->cell_bel_pins[bel_pin].push_back(bel_pin);
-
- connectPort(IdString(chip_info->constants->vcc_net_name), cell->name, bel_pin);
+ if (bind_constants) {
+ PortInfo port_info;
+ port_info.name = bel_pin;
+ port_info.type = PORT_IN;
+
+ auto result = cell->ports.emplace(bel_pin, port_info);
+ if (result.second) {
+ cell->cell_bel_pins[bel_pin].push_back(bel_pin);
+ connectPort(vcc_net_name, cell->name, bel_pin);
+ cell->const_ports.emplace(bel_pin);
+ } else {
+ NPNR_ASSERT(result.first->second.net == getNetByAlias(vcc_net_name));
+ auto result2 = cell->cell_bel_pins.emplace(bel_pin, std::vector<IdString>({bel_pin}));
+ NPNR_ASSERT(result2.first->second.at(0) == bel_pin);
+ NPNR_ASSERT(result2.first->second.size() == 1);
+ }
+ }
continue;
}
@@ -912,9 +966,10 @@ size_t Arch::get_cell_type_index(IdString cell_type) const
return cell_offset;
}
-void Arch::merge_constant_nets() {
- NetInfo* gnd_net = nullptr;
- NetInfo* vcc_net = nullptr;
+void Arch::merge_constant_nets()
+{
+ NetInfo *gnd_net = nullptr;
+ NetInfo *vcc_net = nullptr;
bool need_gnd_source = false;
bool need_vcc_source = false;
@@ -924,7 +979,7 @@ void Arch::merge_constant_nets() {
IdString gnd_cell_port(chip_info->constants->gnd_cell_port);
auto gnd_iter = nets.find(gnd_net_name);
- if(gnd_iter != nets.end()) {
+ if (gnd_iter != nets.end()) {
NPNR_ASSERT(gnd_iter->second->driver.cell != nullptr);
NPNR_ASSERT(gnd_iter->second->driver.cell->type == gnd_cell_type);
NPNR_ASSERT(gnd_iter->second->driver.port == gnd_cell_port);
@@ -940,7 +995,7 @@ void Arch::merge_constant_nets() {
IdString vcc_cell_port(chip_info->constants->vcc_cell_port);
auto vcc_iter = nets.find(vcc_net_name);
- if(vcc_iter != nets.end()) {
+ if (vcc_iter != nets.end()) {
NPNR_ASSERT(vcc_iter->second->driver.cell != nullptr);
NPNR_ASSERT(vcc_iter->second->driver.cell->type == vcc_cell_type);
NPNR_ASSERT(vcc_iter->second->driver.port == vcc_cell_port);
@@ -954,28 +1009,28 @@ void Arch::merge_constant_nets() {
std::vector<IdString> other_gnd_nets;
std::vector<IdString> other_vcc_nets;
- for(auto & net_pair : nets) {
- if(net_pair.first == gnd_net_name) {
+ for (auto &net_pair : nets) {
+ if (net_pair.first == gnd_net_name) {
NPNR_ASSERT(net_pair.second.get() == gnd_net);
continue;
}
- if(net_pair.first == vcc_net_name) {
+ if (net_pair.first == vcc_net_name) {
NPNR_ASSERT(net_pair.second.get() == vcc_net);
continue;
}
NetInfo *net = net_pair.second.get();
- if(net->driver.cell == nullptr) {
+ if (net->driver.cell == nullptr) {
continue;
}
- if(net->driver.cell->type == gnd_cell_type) {
+ if (net->driver.cell->type == gnd_cell_type) {
NPNR_ASSERT(net->driver.port == gnd_cell_port);
other_gnd_nets.push_back(net_pair.first);
- if(need_gnd_source) {
+ if (need_gnd_source) {
IdString driver_cell = net->driver.cell->name;
disconnectPort(driver_cell, gnd_cell_port);
connectPort(gnd_net_name, driver_cell, gnd_cell_port);
@@ -984,7 +1039,7 @@ void Arch::merge_constant_nets() {
NPNR_ASSERT(net->driver.port == gnd_cell_port);
std::vector<PortRef> users_copy = net->users;
- for(const PortRef & port_ref : users_copy) {
+ for (const PortRef &port_ref : users_copy) {
IdString cell = port_ref.cell->name;
disconnectPort(cell, port_ref.port);
connectPort(gnd_net_name, cell, port_ref.port);
@@ -993,12 +1048,12 @@ void Arch::merge_constant_nets() {
continue;
}
- if(net->driver.cell->type == vcc_cell_type) {
+ if (net->driver.cell->type == vcc_cell_type) {
NPNR_ASSERT(net->driver.port == vcc_cell_port);
other_vcc_nets.push_back(net_pair.first);
- if(need_vcc_source) {
+ if (need_vcc_source) {
IdString driver_cell = net->driver.cell->name;
disconnectPort(driver_cell, vcc_cell_port);
connectPort(vcc_net_name, driver_cell, vcc_cell_port);
@@ -1007,7 +1062,7 @@ void Arch::merge_constant_nets() {
NPNR_ASSERT(net->driver.port == vcc_cell_port);
std::vector<PortRef> users_copy = net->users;
- for(const PortRef & port_ref : users_copy) {
+ for (const PortRef &port_ref : users_copy) {
IdString cell = port_ref.cell->name;
disconnectPort(cell, port_ref.port);
connectPort(vcc_net_name, cell, port_ref.port);
@@ -1015,10 +1070,10 @@ void Arch::merge_constant_nets() {
}
}
- for(IdString other_gnd_net : other_gnd_nets) {
- NetInfo * net = getNetByAlias(other_gnd_net);
+ for (IdString other_gnd_net : other_gnd_nets) {
+ NetInfo *net = getNetByAlias(other_gnd_net);
NPNR_ASSERT(net->users.empty());
- if(net->driver.cell) {
+ if (net->driver.cell) {
PortRef driver = net->driver;
IdString cell_to_remove = driver.cell->name;
disconnectPort(driver.cell->name, driver.port);
@@ -1026,10 +1081,10 @@ void Arch::merge_constant_nets() {
}
}
- for(IdString other_vcc_net : other_vcc_nets) {
- NetInfo * net = getNetByAlias(other_vcc_net);
+ for (IdString other_vcc_net : other_vcc_nets) {
+ NetInfo *net = getNetByAlias(other_vcc_net);
NPNR_ASSERT(net->users.empty());
- if(net->driver.cell) {
+ if (net->driver.cell) {
PortRef driver = net->driver;
IdString cell_to_remove = driver.cell->name;
disconnectPort(driver.cell->name, driver.port);
@@ -1037,31 +1092,49 @@ void Arch::merge_constant_nets() {
}
}
- for(IdString other_gnd_net : other_gnd_nets) {
+ for (IdString other_gnd_net : other_gnd_nets) {
NPNR_ASSERT(nets.erase(other_gnd_net));
gnd_net->aliases.push_back(other_gnd_net);
net_aliases[other_gnd_net] = gnd_net_name;
}
- for(IdString other_vcc_net : other_vcc_nets) {
+ for (IdString other_vcc_net : other_vcc_nets) {
NPNR_ASSERT(nets.erase(other_vcc_net));
vcc_net->aliases.push_back(other_vcc_net);
net_aliases[other_vcc_net] = vcc_net_name;
}
- if(need_gnd_source) {
- CellInfo * gnd_cell = createCell(gnd_cell_type, gnd_cell_type);
+ if (need_gnd_source) {
+ CellInfo *gnd_cell = createCell(gnd_cell_type, gnd_cell_type);
gnd_cell->addOutput(gnd_cell_port);
connectPort(gnd_net_name, gnd_cell_type, gnd_cell_port);
}
- if(need_vcc_source) {
- CellInfo * vcc_cell = createCell(vcc_cell_type, vcc_cell_type);
+ if (need_vcc_source) {
+ CellInfo *vcc_cell = createCell(vcc_cell_type, vcc_cell_type);
vcc_cell->addOutput(vcc_cell_port);
connectPort(vcc_net_name, vcc_cell_type, vcc_cell_port);
}
}
+const std::vector<IdString> &Arch::getBelPinsForCellPin(const CellInfo *cell_info, IdString pin) const
+{
+ auto iter = cell_info->cell_bel_pins.find(pin);
+ if (iter == cell_info->cell_bel_pins.end()) {
+ return no_pins;
+ } else {
+ return iter->second;
+ }
+}
+
+void Arch::report_invalid_bel(BelId bel, CellInfo *cell) const
+{
+ int32_t mapping = bel_info(chip_info, bel).pin_map[get_cell_type_index(cell->type)];
+ NPNR_ASSERT(mapping < 0);
+ log_error("Cell %s (%s) cannot be placed at BEL %s (mapping %d)\n", cell->name.c_str(this), cell->type.c_str(this),
+ nameOfBel(bel), mapping);
+}
+
// Instance constraint templates.
template void Arch::ArchConstraints::bindBel(Arch::ArchConstraints::TagState *, const Arch::ConstraintRange);
template void Arch::ArchConstraints::unbindBel(Arch::ArchConstraints::TagState *, const Arch::ConstraintRange);