diff options
| author | Keith Rothman <537074+litghost@users.noreply.github.com> | 2021-02-18 16:51:36 -0800 | 
|---|---|---|
| committer | Keith Rothman <537074+litghost@users.noreply.github.com> | 2021-02-23 14:09:27 -0800 | 
| commit | 15459cae91276f956d2a4734f42162d6afaf1128 (patch) | |
| tree | 1d603225f6f934bcd480f7ce6a440e679e9ca75c /fpga_interchange | |
| parent | cf554f9338db84fa0d12afd83e10f7791e62efa1 (diff) | |
| download | nextpnr-15459cae91276f956d2a4734f42162d6afaf1128.tar.gz nextpnr-15459cae91276f956d2a4734f42162d6afaf1128.tar.bz2 nextpnr-15459cae91276f956d2a4734f42162d6afaf1128.zip | |
Initial working constant network support!
Signed-off-by: Keith Rothman <537074+litghost@users.noreply.github.com>
Diffstat (limited to 'fpga_interchange')
| -rw-r--r-- | fpga_interchange/arch.h | 36 | ||||
| -rw-r--r-- | fpga_interchange/examples/const_wire/wire.v | 4 | ||||
| -rw-r--r-- | fpga_interchange/examples/const_wire/wire.xdc | 4 | ||||
| -rw-r--r-- | fpga_interchange/fpga_interchange.cpp | 115 | 
4 files changed, 145 insertions, 14 deletions
| diff --git a/fpga_interchange/arch.h b/fpga_interchange/arch.h index 541a85ec..0248bf24 100644 --- a/fpga_interchange/arch.h +++ b/fpga_interchange/arch.h @@ -67,7 +67,7 @@ NPNR_PACKED_STRUCT(struct BelInfoPOD {      int16_t site;      int16_t site_variant; // some sites have alternative types      int16_t category; -    int16_t padding; +    int16_t synthetic;      RelPtr<int32_t> pin_map; // Index into CellMapPOD::cell_bel_map  }); @@ -128,7 +128,7 @@ NPNR_PACKED_STRUCT(struct TileTypeInfoPOD {      RelSlice<ConstraintTagPOD> tags; -    RelSlice<int32_t> site_types; +    RelSlice<int32_t> site_types; // constid  });  NPNR_PACKED_STRUCT(struct SiteInstInfoPOD { @@ -902,7 +902,7 @@ struct Arch : ArchAPI<ArchRanges>          auto &constants = chip_info->constants;          BelId bel;          bel.tile = constants->vcc_bel_tile; -        bel.index = constants->vcc_bel_pin; +        bel.index = constants->vcc_bel_index;          return bel;      } @@ -910,7 +910,7 @@ struct Arch : ArchAPI<ArchRanges>          auto &constants = chip_info->constants;          BelId bel;          bel.tile = constants->gnd_bel_tile; -        bel.index = constants->gnd_bel_pin; +        bel.index = constants->gnd_bel_index;          return bel;      } @@ -1682,6 +1682,34 @@ struct Arch : ArchAPI<ArchRanges>          auto &pip_data = pip_info(chip_info, pip);          return site_inst_info(chip_info, pip.tile, pip_data.site);      } + +    // Is this bel synthetic (e.g. added during import process)? +    // +    // This is generally used for constant networks, but can also be used for +    // static partitions. +    bool is_bel_synthetic(BelId bel) const +    { +        const BelInfoPOD & bel_data = bel_info(chip_info, bel); + +        return bel_data.synthetic != 0; +    } + +    // Is this pip synthetic (e.g. added during import process)? +    // +    // This is generally used for constant networks, but can also be used for +    // static partitions. +    bool is_pip_synthetic(PipId pip) const +    { +        auto &pip_data = pip_info(chip_info, pip); +        if(pip_data.site == -1) { +            return pip_data.extra_data == -1; +        } else { +            BelId bel; +            bel.tile = pip.tile; +            bel.index = pip_data.bel; +            return is_bel_synthetic(bel); +        } +    }  };  NEXTPNR_NAMESPACE_END diff --git a/fpga_interchange/examples/const_wire/wire.v b/fpga_interchange/examples/const_wire/wire.v index 7905c92e..5b1ab692 100644 --- a/fpga_interchange/examples/const_wire/wire.v +++ b/fpga_interchange/examples/const_wire/wire.v @@ -1,6 +1,8 @@ -module top(output o, output o2); +module top(output o, output o2, output o3, output o4);  assign o = 1'b0;  assign o2 = 1'b1; +assign o3 = 1'b0; +assign o4 = 1'b1;  endmodule diff --git a/fpga_interchange/examples/const_wire/wire.xdc b/fpga_interchange/examples/const_wire/wire.xdc index beab748e..0d96fc45 100644 --- a/fpga_interchange/examples/const_wire/wire.xdc +++ b/fpga_interchange/examples/const_wire/wire.xdc @@ -1,5 +1,9 @@  set_property PACKAGE_PIN N15 [get_ports o]  set_property PACKAGE_PIN N16 [get_ports o2] +set_property PACKAGE_PIN P17 [get_ports o3] +set_property PACKAGE_PIN R17 [get_ports o4]  set_property IOSTANDARD LVCMOS33 [get_ports o]  set_property IOSTANDARD LVCMOS33 [get_ports o2] +set_property IOSTANDARD LVCMOS33 [get_ports o3] +set_property IOSTANDARD LVCMOS33 [get_ports o4] diff --git a/fpga_interchange/fpga_interchange.cpp b/fpga_interchange/fpga_interchange.cpp index 566524b6..ad1dd76d 100644 --- a/fpga_interchange/fpga_interchange.cpp +++ b/fpga_interchange/fpga_interchange.cpp @@ -62,6 +62,10 @@ static PhysicalNetlist::PhysNetlist::RouteBranch::Builder emit_branch(          const std::unordered_map<PipId, PlaceStrength> &pip_place_strength,          PipId pip,          PhysicalNetlist::PhysNetlist::RouteBranch::Builder branch) { +    if(ctx->is_pip_synthetic(pip)) { +        log_error("FPGA interchange should not emit synthetic pip %s\n", ctx->nameOfPip(pip)); +    } +      const PipInfoPOD & pip_data = pip_info(ctx->chip_info, pip);      const TileTypeInfoPOD & tile_type = loc_info(ctx->chip_info, pip);      const TileInstInfoPOD & tile = ctx->chip_info->tiles[pip.tile]; @@ -185,6 +189,11 @@ static void init_bel_pin(          StringEnumerator * strings,          const BelPin &bel_pin,          PhysicalNetlist::PhysNetlist::RouteBranch::Builder branch) { +    if(ctx->is_bel_synthetic(bel_pin.bel)) { +        log_error("FPGA interchange should not emit synthetic BEL pin %s/%s\n", +                ctx->nameOfBel(bel_pin.bel), bel_pin.pin.c_str(ctx)); +    } +      BelId bel = bel_pin.bel;      IdString pin_name = bel_pin.pin; @@ -248,6 +257,35 @@ static void emit_net(          }      }  } +static void find_non_synthetic_edges(const Context * ctx, WireId root_wire, +        const std::unordered_map<WireId, std::vector<PipId>> &pip_downhill, +        std::vector<PipId> *root_pips) { +    std::vector<WireId> wires_to_expand; + +    wires_to_expand.push_back(root_wire); +    while(!wires_to_expand.empty()) { +        WireId wire = wires_to_expand.back(); +        wires_to_expand.pop_back(); + +        auto downhill_iter = pip_downhill.find(wire); +        if(downhill_iter == pip_downhill.end()) { +            log_warning("Wire %s never entered the real fabric?\n", +                    ctx->nameOfWire(wire)); +            continue; +        } + +        for(PipId pip : pip_downhill.at(wire)) { +            if(!ctx->is_pip_synthetic(pip)) { +                // Stop following edges that are non-synthetic, they will be +                // followed during emit_net +                root_pips->push_back(pip); +            } else { +                // Continue to follow synthetic edges. +                wires_to_expand.push_back(ctx->getPipDstWire(pip)); +            } +        } +    } +}  void FpgaInterchange::write_physical_netlist(const Context * ctx, const std::string &filename) {      ::capnp::MallocMessageBuilder message; @@ -272,9 +310,15 @@ void FpgaInterchange::write_physical_netlist(const Context * ctx, const std::str      size_t number_placements = 0;      for(auto & cell_name : placed_cells) {          const CellInfo & cell = *ctx->cells.at(cell_name); -        if(!ctx->io_port_types.count(cell.type)) { -            number_placements += 1; + +        if(ctx->io_port_types.count(cell.type)) { +            continue; +        } +        if(ctx->is_bel_synthetic(cell.bel)) { +            continue;          } + +        number_placements += 1;      }      std::unordered_map<std::string, std::string> sites; @@ -286,6 +330,9 @@ void FpgaInterchange::write_physical_netlist(const Context * ctx, const std::str          if(ctx->io_port_types.count(cell.type)) {              continue;          } +        if(ctx->is_bel_synthetic(cell.bel)) { +            continue; +        }          IdStringList bel_name = ctx->getBelName(cell.bel);          NPNR_ASSERT(bel_name.size() == 2); @@ -339,16 +386,27 @@ void FpgaInterchange::write_physical_netlist(const Context * ctx, const std::str          auto &net = *net_pair.second;          auto net_out = *net_iter++; -        net_out.setName(strings.get_index(net.name.str(ctx))); +        const CellInfo *driver_cell = net.driver.cell; -        // FIXME: Mark net as signal/vcc/gnd. -        // -        // Also vcc/gnd nets needs to get special handling through inverters. +        // Handle GND and VCC nets. +        if(driver_cell->bel == ctx->get_gnd_bel()) { +            IdString gnd_net_name(ctx->chip_info->constants->gnd_net_name); +            net_out.setName(strings.get_index(gnd_net_name.str(ctx))); +            net_out.setType(PhysicalNetlist::PhysNetlist::NetType::GND); +        } else if(driver_cell->bel == ctx->get_vcc_bel()) { +            IdString vcc_net_name(ctx->chip_info->constants->vcc_net_name); +            net_out.setName(strings.get_index(vcc_net_name.str(ctx))); +            net_out.setType(PhysicalNetlist::PhysNetlist::NetType::VCC); +        } else { +            net_out.setName(strings.get_index(net.name.str(ctx))); +        } + +        // FIXME: Also vcc/gnd nets needs to get special handling through +        // inverters.          std::unordered_map<WireId, BelPin> root_wires;          std::unordered_map<WireId, std::vector<PipId>> pip_downhill;          std::unordered_set<PipId> pips; -        const CellInfo *driver_cell = net.driver.cell;          if (driver_cell != nullptr && driver_cell->bel != BelId()) {              for(IdString bel_pin_name : driver_cell->cell_bel_pins.at(net.driver.port)) {                  BelPin driver_bel_pin; @@ -397,7 +455,27 @@ void FpgaInterchange::write_physical_netlist(const Context * ctx, const std::str              }          } -        auto sources = net_out.initSources(root_wires.size()); +        std::vector<PipId> root_pips; +        std::vector<WireId> roots_to_remove; + +        for(const auto & root_pair : root_wires) { +            WireId root_wire = root_pair.first; +            BelPin src_bel_pin = root_pair.second; + +            if(!ctx->is_bel_synthetic(src_bel_pin.bel)) { +                continue; +            } + +            roots_to_remove.push_back(root_wire); +            find_non_synthetic_edges(ctx, root_wire, pip_downhill, &root_pips); +        } + +        // Remove wires that have a synthetic root. +        for(WireId wire : roots_to_remove) { +            NPNR_ASSERT(root_wires.erase(wire) == 1); +        } + +        auto sources = net_out.initSources(root_wires.size() + root_pips.size());          auto source_iter = sources.begin();          for(const auto & root_pair : root_wires) { @@ -410,11 +488,30 @@ void FpgaInterchange::write_physical_netlist(const Context * ctx, const std::str              emit_net(ctx, &strings, pip_downhill, sinks, &pips, pip_place_strength, root_wire, source_branch);          } +        for(const PipId root : root_pips) { +            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); +            emit_net(ctx, &strings, pip_downhill, sinks, &pips, pip_place_strength, root_wire, source_branch); +        } +          // Any pips that were not part of a tree starting from the source are          // stubs. -        auto stubs = net_out.initStubs(pips.size()); +        size_t real_pips = 0; +        for(PipId pip : pips) { +            if(ctx->is_pip_synthetic(pip)) { +                continue; +            } +            real_pips += 1; +        } +        auto stubs = net_out.initStubs(real_pips);          auto stub_iter = stubs.begin();          for(PipId pip : pips) { +            if(ctx->is_pip_synthetic(pip)) { +                continue; +            }              emit_branch(ctx, &strings, pip_place_strength, pip, *stub_iter++);          }      } | 
