From 06bcde62438dc47a09b5f27c3a7ff6ce4a9ff6c9 Mon Sep 17 00:00:00 2001 From: Keith Rothman <537074+litghost@users.noreply.github.com> Date: Fri, 19 Mar 2021 18:52:27 -0700 Subject: Correct some bugs in writing of physical netlist w.r.t. site sources. Local site sources should have their driving BEL pin included in the net so that the site wire is driven by an output BEL pin. Signed-off-by: Keith Rothman <537074+litghost@users.noreply.github.com> --- fpga_interchange/fpga_interchange.cpp | 104 ++++++++++++++++++++++++++++++---- 1 file changed, 93 insertions(+), 11 deletions(-) diff --git a/fpga_interchange/fpga_interchange.cpp b/fpga_interchange/fpga_interchange.cpp index 9410b117..1be1dfde 100644 --- a/fpga_interchange/fpga_interchange.cpp +++ b/fpga_interchange/fpga_interchange.cpp @@ -114,14 +114,12 @@ static PhysicalNetlist::PhysNetlist::RouteBranch::Builder emit_branch( WireId src_wire = ctx->getPipSrcWire(pip); WireId dst_wire = ctx->getPipDstWire(pip); - IdString src_pin; + NPNR_ASSERT(src_wire.index == bel_data.wires[pip_data.extra_data]); + + IdString src_pin(bel_data.ports[pip_data.extra_data]); + IdString dst_pin; for(IdString pin : ctx->getBelPins(bel)) { - if(ctx->getBelPinWire(bel, pin) == src_wire) { - NPNR_ASSERT(src_pin == IdString()); - src_pin = pin; - } - if(ctx->getBelPinWire(bel, pin) == dst_wire) { NPNR_ASSERT(dst_pin == IdString()); dst_pin = pin; @@ -274,6 +272,65 @@ static void emit_net( } } } + +// Given a site wire, find the source BEL pin. +// +// All site wires should have exactly 1 source BEL pin. +// +// FIXME: Consider making sure that wire_data.bel_pins[0] is always the +// source BEL pin in the BBA generator. +static BelPin find_source(const Context *ctx, WireId source_wire) { + const TileTypeInfoPOD & tile_type = loc_info(ctx->chip_info, source_wire); + const TileWireInfoPOD & wire_data = tile_type.wire_data[source_wire.index]; + + // Make sure this is a site wire, otherwise something odd is happening + // here. + if(wire_data.site == -1) { + return BelPin(); + } + + BelPin source_bel_pin; + for(const BelPin & bel_pin : ctx->getWireBelPins(source_wire)) { + if(ctx->getBelPinType(bel_pin.bel, bel_pin.pin) == PORT_OUT) { + // Synthetic BEL's (like connection to the VCC/GND network) are + // ignored here, because synthetic BEL's don't exists outside of + // the BBA. + if(ctx->is_bel_synthetic(bel_pin.bel)) { + continue; + } + + NPNR_ASSERT(source_bel_pin.bel == BelId()); + source_bel_pin = bel_pin; + } + } + + NPNR_ASSERT(source_bel_pin.bel != BelId()); + NPNR_ASSERT(source_bel_pin.pin != IdString()); + + return source_bel_pin; +} + +// Initial a local signal source (usually VCC/GND). +static PhysicalNetlist::PhysNetlist::RouteBranch::Builder init_local_source( + const Context *ctx, + StringEnumerator * strings, + PhysicalNetlist::PhysNetlist::RouteBranch::Builder source_branch, + PipId root, + const std::unordered_map &pip_place_strength, + WireId *root_wire) { + WireId source_wire = ctx->getPipSrcWire(root); + BelPin source_bel_pin = find_source(ctx, source_wire); + if(source_bel_pin.bel != BelId()) { + // This branch should first emit the BEL pin that is the source, followed + // by the pip that brings the source to the net. + init_bel_pin(ctx, strings, source_bel_pin, source_branch); + + source_branch = source_branch.initBranches(1)[0]; + } + *root_wire = ctx->getPipDstWire(root); + return emit_branch(ctx, strings, pip_place_strength, root, source_branch); +} + static void find_non_synthetic_edges(const Context * ctx, WireId root_wire, const std::unordered_map> &pip_downhill, std::vector *root_pips) { @@ -330,6 +387,15 @@ void FpgaInterchange::write_physical_netlist(const Context * ctx, const std::str for(auto & cell_name : placed_cells) { const CellInfo & cell = *ctx->cells.at(cell_name); + if(cell.bel == BelId()) { + continue; + } + + if(!ctx->isBelLocationValid(cell.bel)) { + log_error("Cell '%s' is placed at BEL '%s', but this location is currently invalid. Not writing physical netlist.\n", + cell.name.c_str(ctx), ctx->nameOfBel(cell.bel)); + } + if(ctx->is_bel_synthetic(cell.bel)) { continue; } @@ -345,6 +411,13 @@ void FpgaInterchange::write_physical_netlist(const Context * ctx, const std::str for(auto & cell_name : placed_cells) { const CellInfo & cell = *ctx->cells.at(cell_name); + + if(cell.bel == BelId()) { + continue; + } + + NPNR_ASSERT(ctx->isBelLocationValid(cell.bel)); + if(ctx->is_bel_synthetic(cell.bel)) { continue; } @@ -446,7 +519,7 @@ void FpgaInterchange::write_physical_netlist(const Context * ctx, const std::str std::unordered_map> pip_downhill; std::unordered_set pips; - if (driver_cell != nullptr && driver_cell->bel != BelId()) { + if (driver_cell != nullptr && driver_cell->bel != BelId() && ctx->isBelLocationValid(driver_cell->bel)) { for(IdString bel_pin_name : driver_cell->cell_bel_pins.at(net.driver.port)) { BelPin driver_bel_pin; driver_bel_pin.bel = driver_cell->bel; @@ -461,8 +534,17 @@ void FpgaInterchange::write_physical_netlist(const Context * ctx, const std::str std::unordered_map> sinks; for(const auto &port_ref : net.users) { - if(port_ref.cell != nullptr && port_ref.cell->bel != BelId()) { - for(IdString bel_pin_name : port_ref.cell->cell_bel_pins.at(port_ref.port)) { + if(port_ref.cell != nullptr && port_ref.cell->bel != BelId() && ctx->isBelLocationValid(port_ref.cell->bel)) { + auto pin_iter = port_ref.cell->cell_bel_pins.find(port_ref.port); + if(pin_iter == port_ref.cell->cell_bel_pins.end()) { + log_warning("Cell %s port %s on net %s is legal, but has no BEL pins?\n", + port_ref.cell->name.c_str(ctx), + port_ref.port.c_str(ctx), + net.name.c_str(ctx)); + continue; + } + + for(IdString bel_pin_name : pin_iter->second) { BelPin sink_bel_pin; sink_bel_pin.bel = port_ref.cell->bel; sink_bel_pin.pin = bel_pin_name; @@ -531,8 +613,8 @@ void FpgaInterchange::write_physical_netlist(const Context * ctx, const std::str PhysicalNetlist::PhysNetlist::RouteBranch::Builder source_branch = *source_iter++; NPNR_ASSERT(pips.erase(root) == 1); - WireId root_wire = ctx->getPipDstWire(root); - source_branch = emit_branch(ctx, &strings, pip_place_strength, root, source_branch); + WireId root_wire; + source_branch = init_local_source(ctx, &strings, source_branch, root, pip_place_strength, &root_wire); emit_net(ctx, &strings, pip_downhill, sinks, &pips, pip_place_strength, root_wire, source_branch); } -- cgit v1.2.3