/* * nextpnr -- Next Generation Place and Route * * Copyright (C) 2018 David Shah * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * */ #include #include #include #include "design_utils.h" #include "log.h" #include "util.h" NEXTPNR_NAMESPACE_BEGIN static bool is_nextpnr_iob(Context *ctx, CellInfo *cell) { return cell->type == ctx->id("$nextpnr_ibuf") || cell->type == ctx->id("$nextpnr_obuf") || cell->type == ctx->id("$nextpnr_iobuf"); } static bool is_trellis_io(const Context *ctx, const CellInfo *cell) { return cell->type == ctx->id("TRELLIS_IO"); } // Simple "packer" to remove nextpnr IOBUFs, this assumes IOBUFs are manually instantiated void pack_io(Context *ctx) { std::unordered_set packed_cells; std::vector> new_cells; log_info("Packing IOs..\n"); for (auto cell : sorted(ctx->cells)) { CellInfo *ci = cell.second; if (is_nextpnr_iob(ctx, ci)) { CellInfo *trio = nullptr; if (ci->type == ctx->id("$nextpnr_ibuf") || ci->type == ctx->id("$nextpnr_iobuf")) { trio = net_only_drives(ctx, ci->ports.at(ctx->id("O")).net, is_trellis_io, ctx->id("B"), true, ci); } else if (ci->type == ctx->id("$nextpnr_obuf")) { trio = net_only_drives(ctx, ci->ports.at(ctx->id("I")).net, is_trellis_io, ctx->id("B"), true, ci); } if (trio != nullptr) { // Trivial case, TRELLIS_IO used. Just destroy the net and the // iobuf log_info("%s feeds TRELLIS_IO %s, removing %s %s.\n", ci->name.c_str(ctx), trio->name.c_str(ctx), ci->type.c_str(ctx), ci->name.c_str(ctx)); NetInfo *net = trio->ports.at(ctx->id("B")).net; if (net != nullptr) { ctx->nets.erase(net->name); trio->ports.at(ctx->id("B")).net = nullptr; } if (ci->type == ctx->id("$nextpnr_iobuf")) { NetInfo *net2 = ci->ports.at(ctx->id("I")).net; if (net2 != nullptr) { ctx->nets.erase(net2->name); } } } else { log_error("TRELLIS_IO required on all top level IOs...\n"); } packed_cells.insert(ci->name); std::copy(ci->attrs.begin(), ci->attrs.end(), std::inserter(trio->attrs, trio->attrs.begin())); } } for (auto pcell : packed_cells) { ctx->cells.erase(pcell); } for (auto &ncell : new_cells) { ctx->cells[ncell->name] = std::move(ncell); } } // Main pack function bool Arch::pack() { Context *ctx = getCtx(); try { log_break(); pack_io(ctx); log_info("Checksum: 0x%08x\n", ctx->checksum()); return true; } catch (log_execution_error_exception) { return false; } } NEXTPNR_NAMESPACE_END