aboutsummaryrefslogtreecommitdiffstats
path: root/fpga_interchange/arch.cc
diff options
context:
space:
mode:
Diffstat (limited to 'fpga_interchange/arch.cc')
-rw-r--r--fpga_interchange/arch.cc197
1 files changed, 196 insertions, 1 deletions
diff --git a/fpga_interchange/arch.cc b/fpga_interchange/arch.cc
index dc99f1cd..3b603e5e 100644
--- a/fpga_interchange/arch.cc
+++ b/fpga_interchange/arch.cc
@@ -158,6 +158,7 @@ Arch::Arch(ArchArgs args) : args(args)
int tile_type_index = 0;
size_t max_tag_count = 0;
+
for (const TileTypeInfoPOD &tile_type : chip_info->tile_types) {
max_tag_count = std::max(max_tag_count, tile_type.tags.size());
@@ -192,6 +193,50 @@ Arch::Arch(ArchArgs args) : args(args)
}
}
+ // Initially LutElement vectors for each tile type.
+ tile_type_index = 0;
+ lut_elements.resize(chip_info->tile_types.size());
+ for (const TileTypeInfoPOD &tile_type : chip_info->tile_types) {
+ std::vector<LutElement> &elements = lut_elements[tile_type_index++];
+ elements.reserve(tile_type.lut_elements.size());
+ for (auto &lut_element : tile_type.lut_elements) {
+ elements.emplace_back();
+
+ LutElement &element = elements.back();
+ element.width = lut_element.width;
+ for (auto &lut_bel : lut_element.lut_bels) {
+ auto result = element.lut_bels.emplace(IdString(lut_bel.name), LutBel());
+ NPNR_ASSERT(result.second);
+ LutBel &lut = result.first->second;
+
+ lut.low_bit = lut_bel.low_bit;
+ lut.high_bit = lut_bel.high_bit;
+
+ lut.pins.reserve(lut_bel.pins.size());
+ for (size_t i = 0; i < lut_bel.pins.size(); ++i) {
+ IdString pin(lut_bel.pins[i]);
+ lut.pins.push_back(pin);
+ lut.pin_to_index[pin] = i;
+ }
+ }
+
+ element.compute_pin_order();
+ }
+ }
+
+ // Map lut cell types to their LutCellPOD
+ for (const LutCellPOD &lut_cell : chip_info->cell_map->lut_cells) {
+ IdString cell_type(lut_cell.cell);
+ auto result = lut_cells.emplace(cell_type, &lut_cell);
+ NPNR_ASSERT(result.second);
+ }
+
+ raw_bin_constant = std::regex("[01]+", std::regex_constants::ECMAScript | std::regex_constants::optimize);
+ verilog_bin_constant =
+ std::regex("([0-9]+)'b([01]+)", std::regex_constants::ECMAScript | std::regex_constants::optimize);
+ verilog_hex_constant =
+ std::regex("([0-9]+)'h([0-9a-fA-F]+)", std::regex_constants::ECMAScript | std::regex_constants::optimize);
+
default_tags.resize(max_tag_count);
}
@@ -603,6 +648,7 @@ bool Arch::getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay
bool Arch::pack()
{
+ decode_lut_cells();
merge_constant_nets();
pack_ports();
return true;
@@ -666,11 +712,71 @@ bool Arch::route()
} else {
log_error("FPGA interchange architecture does not support router '%s'\n", router.c_str());
}
+
+ if (result) {
+ result = route_vcc_to_unused_lut_pins();
+ }
+
getCtx()->attrs[getCtx()->id("step")] = std::string("route");
archInfoToAttributes();
+
return result;
}
+bool Arch::route_vcc_to_unused_lut_pins() {
+ std::string router = str_or_default(settings, id("router"), defaultRouter);
+
+ // Fixup LUT vcc pins.
+ IdString vcc_net_name(chip_info->constants->vcc_net_name);
+ for (BelId bel : getBels()) {
+ CellInfo *cell = getBoundBelCell(bel);
+ if (cell == nullptr) {
+ continue;
+ }
+
+ if (cell->lut_cell.vcc_pins.empty()) {
+ continue;
+ }
+
+ for (auto bel_pin : cell->lut_cell.vcc_pins) {
+ PortInfo port_info;
+ port_info.name = bel_pin;
+ port_info.type = PORT_IN;
+ 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 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);
+ }
+ }
+ }
+
+ if (router == "router1") {
+ return router1(getCtx(), Router1Cfg(getCtx()));
+ } else if (router == "router2") {
+ router2(getCtx(), Router2Cfg(getCtx()));
+ return true;
+ } else {
+ log_error("FPGA interchange architecture does not support router '%s'\n", router.c_str());
+ }
+}
+
// -----------------------------------------------------------------------
std::vector<GraphicElement> Arch::getDecalGraphics(DecalId decal) const { return {}; }
@@ -791,7 +897,20 @@ const std::vector<std::string> Arch::availableRouters = {"router1", "router2"};
void Arch::map_cell_pins(CellInfo *cell, int32_t mapping, bool bind_constants)
{
cell->cell_mapping = mapping;
- cell->cell_bel_pins.clear();
+ if (cell->lut_cell.pins.empty()) {
+ cell->cell_bel_pins.clear();
+ } else {
+ std::vector<IdString> cell_pin_to_remove;
+ for (auto port_pair : cell->cell_bel_pins) {
+ if (!cell->lut_cell.lut_pins.count(port_pair.first)) {
+ cell_pin_to_remove.push_back(port_pair.first);
+ }
+ }
+
+ for (IdString cell_pin : cell_pin_to_remove) {
+ NPNR_ASSERT(cell->cell_bel_pins.erase(cell_pin));
+ }
+ }
for (IdString const_port : cell->const_ports) {
NPNR_ASSERT(cell->ports.erase(const_port));
}
@@ -805,6 +924,11 @@ void Arch::map_cell_pins(CellInfo *cell, int32_t mapping, bool bind_constants)
IdString cell_pin(pin_map.cell_pin);
IdString bel_pin(pin_map.bel_pin);
+ // Skip assigned LUT pins, as they are already mapped!
+ if (cell->lut_cell.lut_pins.count(cell_pin) && cell->cell_bel_pins.count(cell_pin)) {
+ continue;
+ }
+
if (cell_pin.str(this) == "GND") {
if (bind_constants) {
PortInfo port_info;
@@ -869,11 +993,17 @@ void Arch::map_cell_pins(CellInfo *cell, int32_t mapping, bool bind_constants)
IdString cell_pin(pin_map.cell_pin);
IdString bel_pin(pin_map.bel_pin);
+ // Skip assigned LUT pins, as they are already mapped!
+ if (cell->lut_cell.lut_pins.count(cell_pin) && cell->cell_bel_pins.count(cell_pin)) {
+ continue;
+ }
+
if (cell_pin.str(this) == "GND") {
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) {
@@ -895,6 +1025,7 @@ void Arch::map_cell_pins(CellInfo *cell, int32_t mapping, bool 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) {
@@ -1135,6 +1266,70 @@ void Arch::report_invalid_bel(BelId bel, CellInfo *cell) const
nameOfBel(bel), mapping);
}
+void Arch::read_lut_equation(nextpnr::DynamicBitarray<> *equation, const Property &equation_parameter) const
+{
+ equation->fill(false);
+ std::string eq_str = equation_parameter.as_string();
+ std::smatch results;
+ if (std::regex_match(eq_str, results, raw_bin_constant)) {
+ size_t bit_idx = 0;
+ const std::string &bits = results[0];
+ NPNR_ASSERT(bits.size() <= equation->size());
+ for (auto bit = bits.rbegin(); bit != bits.rend(); ++bit) {
+ if (*bit == '0') {
+ equation->set(bit_idx++, false);
+ } else {
+ NPNR_ASSERT(*bit == '1');
+ equation->set(bit_idx++, true);
+ }
+ }
+ } else if (std::regex_match(eq_str, results, verilog_bin_constant)) {
+ int iwidth = std::stoi(results[1]);
+ NPNR_ASSERT(iwidth >= 0);
+ size_t width = iwidth;
+ std::string bits = results[2];
+ NPNR_ASSERT(width <= equation->size());
+ NPNR_ASSERT(bits.size() <= width);
+ size_t bit_idx = 0;
+ for (auto bit = bits.rbegin(); bit != bits.rend(); ++bit) {
+ if (*bit == '0') {
+ equation->set(bit_idx++, false);
+ } else {
+ NPNR_ASSERT(*bit == '1');
+ equation->set(bit_idx++, true);
+ }
+ }
+ } else {
+ NPNR_ASSERT(false);
+ }
+}
+
+void Arch::decode_lut_cells()
+{
+ for (auto &cell_pair : cells) {
+ CellInfo *cell = cell_pair.second.get();
+ auto iter = lut_cells.find(cell->type);
+ if (iter == lut_cells.end()) {
+ cell->lut_cell.pins.clear();
+ cell->lut_cell.equation.clear();
+ continue;
+ }
+
+ const LutCellPOD &lut_cell = *iter->second;
+
+ cell->lut_cell.pins.reserve(lut_cell.input_pins.size());
+ for (uint32_t pin : lut_cell.input_pins) {
+ cell->lut_cell.pins.push_back(IdString(pin));
+ cell->lut_cell.lut_pins.emplace(IdString(pin));
+ }
+
+ IdString equation_parameter(lut_cell.parameter);
+ const Property &equation = cell->params.at(equation_parameter);
+ cell->lut_cell.equation.resize(1 << cell->lut_cell.pins.size());
+ read_lut_equation(&cell->lut_cell.equation, equation);
+ }
+}
+
// 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);