diff --git a/CMakeLists.txt b/CMakeLists.txt index e9d25abc..32063af6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -219,6 +219,7 @@ endforeach (family) file(GLOB_RECURSE CLANGFORMAT_FILES *.cc *.h) string(REGEX REPLACE "[^;]*/ice40/chipdbs/chipdb-[^;]*.cc" "" CLANGFORMAT_FILES "${CLANGFORMAT_FILES}") +string(REGEX REPLACE "[^;]*/ecp5/chipdbs/chipdb-[^;]*.cc" "" CLANGFORMAT_FILES "${CLANGFORMAT_FILES}") string(REGEX REPLACE "[^;]*/3rdparty[^;]*" "" CLANGFORMAT_FILES "${CLANGFORMAT_FILES}") string(REGEX REPLACE "[^;]*/generated[^;]*" "" CLANGFORMAT_FILES "${CLANGFORMAT_FILES}") diff --git a/ecp5/arch.cc b/ecp5/arch.cc index 6708c339..e80ad829 100644 --- a/ecp5/arch.cc +++ b/ecp5/arch.cc @@ -116,7 +116,6 @@ Arch::Arch(ArchArgs args) : args(args) log_error("Unsupported ECP5 chip type.\n"); } #endif - } // ----------------------------------------------------------------------- @@ -272,7 +271,8 @@ BelId Arch::getPackagePinBel(const std::string &pin) const { return BelId(); } std::string Arch::getBelPackagePin(BelId bel) const { return ""; } // ----------------------------------------------------------------------- -void Arch::estimatePosition(BelId bel, int &x, int &y, bool &gb) const { +void Arch::estimatePosition(BelId bel, int &x, int &y, bool &gb) const +{ x = bel.location.x; y = bel.location.y; gb = false; @@ -318,7 +318,6 @@ bool Arch::isBelLocationValid(BelId bel) const { return true; } // ----------------------------------------------------------------------- - bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, delay_t &delay) const { return false; @@ -328,5 +327,4 @@ IdString Arch::getPortClock(const CellInfo *cell, IdString port) const { return bool Arch::isClockPort(const CellInfo *cell, IdString port) const { return false; } - NEXTPNR_NAMESPACE_END diff --git a/ecp5/main.cc b/ecp5/main.cc index a9b02537..245d1cc3 100644 --- a/ecp5/main.cc +++ b/ecp5/main.cc @@ -29,18 +29,18 @@ #endif #include #include -#include #include +#include #include "log.h" #include "nextpnr.h" #include "version.h" +#include "design_utils.h" +#include "jsonparse.h" +#include "pack.h" #include "place_sa.h" #include "route.h" -#include "design_utils.h" #include "timing.h" -#include "jsonparse.h" - USING_NEXTPNR_NAMESPACE @@ -123,8 +123,8 @@ int main(int argc, char *argv[]) if (!parse_json_file(f, filename, &ctx)) log_error("Loading design failed.\n"); - //if (!pack_design(&ctx) && !ctx.force) - // log_error("Packing design failed.\n"); + if (!pack_design(&ctx) && !ctx.force) + log_error("Packing design failed.\n"); if (vm.count("freq")) ctx.target_freq = vm["freq"].as() * 1e6; assign_budget(&ctx); @@ -139,7 +139,6 @@ int main(int argc, char *argv[]) ctx.check(); if (!route_design(&ctx) && !ctx.force) log_error("Routing design failed.\n"); - } #ifndef NO_PYTHON diff --git a/ecp5/pack.cc b/ecp5/pack.cc new file mode 100644 index 00000000..7f54c231 --- /dev/null +++ b/ecp5/pack.cc @@ -0,0 +1,99 @@ +/* + * 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 "pack.h" +#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 pack_design(Context *ctx) +{ + 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 diff --git a/ecp5/pack.h b/ecp5/pack.h new file mode 100644 index 00000000..cc051a41 --- /dev/null +++ b/ecp5/pack.h @@ -0,0 +1,31 @@ +/* + * 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. + * + */ + +#ifndef PACK_H +#define PACK_H + +#include "nextpnr.h" + +NEXTPNR_NAMESPACE_BEGIN + +bool pack_design(Context *ctx); + +NEXTPNR_NAMESPACE_END + +#endif // ROUTE_H