diff options
author | Eddie Hung <e.hung@imperial.ac.uk> | 2018-07-24 22:20:10 -0700 |
---|---|---|
committer | Eddie Hung <e.hung@imperial.ac.uk> | 2018-07-24 22:20:10 -0700 |
commit | 9382938661613b84e3ad3155e414aaae2fa87da2 (patch) | |
tree | 107c14811cf2e91c82ee4f9ea983260ee7acea8c /ecp5 | |
parent | 4920cf18fa1128758dac2ffd12bf88d194863f17 (diff) | |
parent | 32c7247785f48b2307e559a0af50d9387bda8b49 (diff) | |
download | nextpnr-9382938661613b84e3ad3155e414aaae2fa87da2.tar.gz nextpnr-9382938661613b84e3ad3155e414aaae2fa87da2.tar.bz2 nextpnr-9382938661613b84e3ad3155e414aaae2fa87da2.zip |
Merge branch 'master' into redist_slack
Diffstat (limited to 'ecp5')
-rw-r--r-- | ecp5/arch.cc | 46 | ||||
-rw-r--r-- | ecp5/arch.h | 3 | ||||
-rw-r--r-- | ecp5/arch_place.cc | 7 | ||||
-rw-r--r-- | ecp5/arch_pybindings.cc | 125 | ||||
-rw-r--r-- | ecp5/bitstream.cc | 56 | ||||
-rw-r--r-- | ecp5/main.cc | 4 |
6 files changed, 195 insertions, 46 deletions
diff --git a/ecp5/arch.cc b/ecp5/arch.cc index 371dbb12..2e8f7987 100644 --- a/ecp5/arch.cc +++ b/ecp5/arch.cc @@ -192,17 +192,20 @@ BelId Arch::getBelByName(IdString name) const return ret; } -BelRange Arch::getBelsAtSameTile(BelId bel) const +BelRange Arch::getBelsByTile(int x, int y) const { BelRange br; - NPNR_ASSERT(bel != BelId()); - br.b.cursor_tile = bel.location.y * chip_info->width + bel.location.x; - br.e.cursor_tile = bel.location.y * chip_info->width + bel.location.x; + + br.b.cursor_tile = y * chip_info->width + x; + br.e.cursor_tile = y * chip_info->width + x; br.b.cursor_index = 0; - br.e.cursor_index = locInfo(bel)->num_bels - 1; + br.e.cursor_index = chip_info->locations[chip_info->location_type[br.b.cursor_tile]].num_bels - 1; br.b.chip = chip_info; br.e.chip = chip_info; - ++br.e; + if (br.e.cursor_index == -1) + ++br.e.cursor_index; + else + ++br.e; return br; } @@ -278,6 +281,7 @@ PipId Arch::getPipByName(IdString name) const Location loc; std::string basename; std::tie(loc.x, loc.y, basename) = split_identifier_name(name.str(this)); + ret.location = loc; const LocationTypePOD *loci = locInfo(ret); for (int i = 0; i < loci->num_pips; i++) { PipId curr; @@ -285,6 +289,8 @@ PipId Arch::getPipByName(IdString name) const curr.index = i; pip_by_name[getPipName(curr)] = curr; } + if (pip_by_name.find(name) == pip_by_name.end()) + NPNR_ASSERT_FALSE_STR("no pip named " + name.str(this)); return pip_by_name[name]; } @@ -399,36 +405,8 @@ BelId Arch::getBelByLocation(Loc loc) const return BelId(); } -BelRange Arch::getBelsByTile(int x, int y) const -{ - BelRange br; - - int num_bels = 0; - - if (x < chip_info->width && y < chip_info->height) { - const LocationTypePOD &locI = chip_info->locations[chip_info->location_type[y * chip_info->width + x]]; - num_bels = locI.num_bels; - } - - br.b.cursor_tile = y * chip_info->width + x; - br.e.cursor_tile = y * chip_info->width + x; - br.b.cursor_index = 0; - br.e.cursor_index = num_bels - 1; - br.b.chip = chip_info; - br.e.chip = chip_info; - ++br.e; - return br; -} - // ----------------------------------------------------------------------- -void Arch::estimatePosition(BelId bel, int &x, int &y, bool &gb) const -{ - x = bel.location.x; - y = bel.location.y; - gb = false; -} - delay_t Arch::estimateDelay(WireId src, WireId dst) const { return 200 * (abs(src.location.x - dst.location.x) + abs(src.location.y - dst.location.y)); diff --git a/ecp5/arch.h b/ecp5/arch.h index c2efb2bd..7a8f5b36 100644 --- a/ecp5/arch.h +++ b/ecp5/arch.h @@ -482,8 +482,6 @@ struct Arch : BaseCtx return range; } - BelRange getBelsAtSameTile(BelId bel) const; - BelType getBelType(BelId bel) const { NPNR_ASSERT(bel != BelId()); @@ -752,7 +750,6 @@ struct Arch : BaseCtx // ------------------------------------------------- - void estimatePosition(BelId bel, int &x, int &y, bool &gb) const; delay_t estimateDelay(WireId src, WireId dst) const; delay_t getDelayEpsilon() const { return 20; } delay_t getRipupDelayPenalty() const { return 200; } diff --git a/ecp5/arch_place.cc b/ecp5/arch_place.cc index 22ebab67..84432043 100644 --- a/ecp5/arch_place.cc +++ b/ecp5/arch_place.cc @@ -66,7 +66,8 @@ bool Arch::isBelLocationValid(BelId bel) const { if (getBelType(bel) == TYPE_TRELLIS_SLICE) { std::vector<const CellInfo *> bel_cells; - for (auto bel_other : getBelsAtSameTile(bel)) { + Loc bel_loc = getBelLocation(bel); + for (auto bel_other : getBelsByTile(bel_loc.x, bel_loc.y)) { IdString cell_other = getBoundBelCell(bel_other); if (cell_other != IdString()) { const CellInfo *ci_other = cells.at(cell_other).get(); @@ -89,8 +90,8 @@ bool Arch::isValidBelForCell(CellInfo *cell, BelId bel) const NPNR_ASSERT(getBelType(bel) == TYPE_TRELLIS_SLICE); std::vector<const CellInfo *> bel_cells; - - for (auto bel_other : getBelsAtSameTile(bel)) { + Loc bel_loc = getBelLocation(bel); + for (auto bel_other : getBelsByTile(bel_loc.x, bel_loc.y)) { IdString cell_other = getBoundBelCell(bel_other); if (cell_other != IdString() && bel_other != bel) { const CellInfo *ci_other = cells.at(cell_other).get(); diff --git a/ecp5/arch_pybindings.cc b/ecp5/arch_pybindings.cc index 8310c3a1..c261c3ec 100644 --- a/ecp5/arch_pybindings.cc +++ b/ecp5/arch_pybindings.cc @@ -2,7 +2,7 @@ * nextpnr -- Next Generation Place and Route * * Copyright (C) 2018 Clifford Wolf <clifford@symbioticeda.com> - * Copyright (C) 2018 David Shah <dave@ds0.me> + * Copyright (C) 2018 David Shah <david@symbioticeda.com> * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -20,13 +20,132 @@ #ifndef NO_PYTHON +#include "arch_pybindings.h" #include "nextpnr.h" #include "pybindings.h" NEXTPNR_NAMESPACE_BEGIN -void arch_wrap_python() {} +void arch_wrap_python() +{ + using namespace PythonConversion; + class_<ArchArgs>("ArchArgs").def_readwrite("type", &ArchArgs::type); + + class_<BelId>("BelId").def_readwrite("index", &BelId::index); + + class_<WireId>("WireId").def_readwrite("index", &WireId::index); + + class_<PipId>("PipId").def_readwrite("index", &PipId::index); + + class_<BelPin>("BelPin").def_readwrite("bel", &BelPin::bel).def_readwrite("pin", &BelPin::pin); + + enum_<PortPin>("PortPin") +#define X(t) .value("PIN_" #t, PIN_##t) + +#include "portpins.inc" + ; +#undef X + + auto arch_cls = class_<Arch, Arch *, bases<BaseCtx>, boost::noncopyable>("Arch", init<ArchArgs>()); + auto ctx_cls = class_<Context, Context *, bases<Arch>, boost::noncopyable>("Context", no_init) + .def("checksum", &Context::checksum) + .def("pack", &Context::pack) + .def("place", &Context::place) + .def("route", &Context::route); + + fn_wrapper_1a<Context, decltype(&Context::getBelType), &Context::getBelType, conv_to_str<BelType>, + conv_from_str<BelId>>::def_wrap(ctx_cls, "getBelType"); + fn_wrapper_1a<Context, decltype(&Context::checkBelAvail), &Context::checkBelAvail, pass_through<bool>, + conv_from_str<BelId>>::def_wrap(ctx_cls, "checkBelAvail"); + fn_wrapper_1a<Context, decltype(&Context::getBelChecksum), &Context::getBelChecksum, pass_through<uint32_t>, + conv_from_str<BelId>>::def_wrap(ctx_cls, "getBelChecksum"); + fn_wrapper_3a_v<Context, decltype(&Context::bindBel), &Context::bindBel, conv_from_str<BelId>, + conv_from_str<IdString>, pass_through<PlaceStrength>>::def_wrap(ctx_cls, "bindBel"); + fn_wrapper_1a_v<Context, decltype(&Context::unbindBel), &Context::unbindBel, conv_from_str<BelId>>::def_wrap( + ctx_cls, "unbindBel"); + fn_wrapper_1a<Context, decltype(&Context::getBoundBelCell), &Context::getBoundBelCell, conv_to_str<IdString>, + conv_from_str<BelId>>::def_wrap(ctx_cls, "getBoundBelCell"); + fn_wrapper_1a<Context, decltype(&Context::getConflictingBelCell), &Context::getConflictingBelCell, + conv_to_str<IdString>, conv_from_str<BelId>>::def_wrap(ctx_cls, "getConflictingBelCell"); + fn_wrapper_0a<Context, decltype(&Context::getBels), &Context::getBels, wrap_context<BelRange>>::def_wrap(ctx_cls, + "getBels"); + + fn_wrapper_2a<Context, decltype(&Context::getBelPinWire), &Context::getBelPinWire, conv_to_str<WireId>, + conv_from_str<BelId>, conv_from_str<PortPin>>::def_wrap(ctx_cls, "getBelPinWire"); + fn_wrapper_1a<Context, decltype(&Context::getWireBelPins), &Context::getWireBelPins, wrap_context<BelPinRange>, + conv_from_str<WireId>>::def_wrap(ctx_cls, "getWireBelPins"); + + fn_wrapper_1a<Context, decltype(&Context::getWireChecksum), &Context::getWireChecksum, pass_through<uint32_t>, + conv_from_str<WireId>>::def_wrap(ctx_cls, "getWireChecksum"); + fn_wrapper_3a_v<Context, decltype(&Context::bindWire), &Context::bindWire, conv_from_str<WireId>, + conv_from_str<IdString>, pass_through<PlaceStrength>>::def_wrap(ctx_cls, "bindWire"); + fn_wrapper_1a_v<Context, decltype(&Context::unbindWire), &Context::unbindWire, conv_from_str<WireId>>::def_wrap( + ctx_cls, "unbindWire"); + fn_wrapper_1a<Context, decltype(&Context::checkWireAvail), &Context::checkWireAvail, pass_through<bool>, + conv_from_str<WireId>>::def_wrap(ctx_cls, "checkWireAvail"); + fn_wrapper_1a<Context, decltype(&Context::getBoundWireNet), &Context::getBoundWireNet, conv_to_str<IdString>, + conv_from_str<WireId>>::def_wrap(ctx_cls, "getBoundWireNet"); + fn_wrapper_1a<Context, decltype(&Context::getConflictingWireNet), &Context::getConflictingWireNet, + conv_to_str<IdString>, conv_from_str<WireId>>::def_wrap(ctx_cls, "getConflictingWireNet"); + + fn_wrapper_0a<Context, decltype(&Context::getWires), &Context::getWires, wrap_context<WireRange>>::def_wrap( + ctx_cls, "getWires"); + + fn_wrapper_0a<Context, decltype(&Context::getPips), &Context::getPips, wrap_context<AllPipRange>>::def_wrap( + ctx_cls, "getPips"); + fn_wrapper_1a<Context, decltype(&Context::getPipChecksum), &Context::getPipChecksum, pass_through<uint32_t>, + conv_from_str<PipId>>::def_wrap(ctx_cls, "getPipChecksum"); + fn_wrapper_3a_v<Context, decltype(&Context::bindPip), &Context::bindPip, conv_from_str<PipId>, + conv_from_str<IdString>, pass_through<PlaceStrength>>::def_wrap(ctx_cls, "bindPip"); + fn_wrapper_1a_v<Context, decltype(&Context::unbindPip), &Context::unbindPip, conv_from_str<PipId>>::def_wrap( + ctx_cls, "unbindPip"); + fn_wrapper_1a<Context, decltype(&Context::checkPipAvail), &Context::checkPipAvail, pass_through<bool>, + conv_from_str<PipId>>::def_wrap(ctx_cls, "checkPipAvail"); + fn_wrapper_1a<Context, decltype(&Context::getBoundPipNet), &Context::getBoundPipNet, conv_to_str<IdString>, + conv_from_str<PipId>>::def_wrap(ctx_cls, "getBoundPipNet"); + fn_wrapper_1a<Context, decltype(&Context::getConflictingPipNet), &Context::getConflictingPipNet, + conv_to_str<IdString>, conv_from_str<PipId>>::def_wrap(ctx_cls, "getConflictingPipNet"); + + fn_wrapper_1a<Context, decltype(&Context::getPipsDownhill), &Context::getPipsDownhill, wrap_context<PipRange>, + conv_from_str<WireId>>::def_wrap(ctx_cls, "getPipsDownhill"); + fn_wrapper_1a<Context, decltype(&Context::getPipsUphill), &Context::getPipsUphill, wrap_context<PipRange>, + conv_from_str<WireId>>::def_wrap(ctx_cls, "getPipsUphill"); + fn_wrapper_1a<Context, decltype(&Context::getWireAliases), &Context::getWireAliases, wrap_context<PipRange>, + conv_from_str<WireId>>::def_wrap(ctx_cls, "getWireAliases"); + + fn_wrapper_1a<Context, decltype(&Context::getPipSrcWire), &Context::getPipSrcWire, conv_to_str<WireId>, + conv_from_str<PipId>>::def_wrap(ctx_cls, "getPipSrcWire"); + fn_wrapper_1a<Context, decltype(&Context::getPipDstWire), &Context::getPipDstWire, conv_to_str<WireId>, + conv_from_str<PipId>>::def_wrap(ctx_cls, "getPipDstWire"); + fn_wrapper_1a<Context, decltype(&Context::getPipDelay), &Context::getPipDelay, pass_through<DelayInfo>, + conv_from_str<PipId>>::def_wrap(ctx_cls, "getPipDelay"); + + fn_wrapper_1a<Context, decltype(&Context::getPackagePinBel), &Context::getPackagePinBel, conv_to_str<BelId>, + pass_through<std::string>>::def_wrap(ctx_cls, "getPackagePinBel"); + fn_wrapper_1a<Context, decltype(&Context::getBelPackagePin), &Context::getBelPackagePin, pass_through<std::string>, + conv_from_str<BelId>>::def_wrap(ctx_cls, "getBelPackagePin"); + + fn_wrapper_0a<Context, decltype(&Context::getChipName), &Context::getChipName, pass_through<std::string>>::def_wrap( + ctx_cls, "getChipName"); + fn_wrapper_0a<Context, decltype(&Context::archId), &Context::archId, conv_to_str<IdString>>::def_wrap(ctx_cls, + "archId"); + + typedef std::unordered_map<IdString, std::unique_ptr<CellInfo>> CellMap; + typedef std::unordered_map<IdString, std::unique_ptr<NetInfo>> NetMap; + + readonly_wrapper<Context, decltype(&Context::cells), &Context::cells, wrap_context<CellMap &>>::def_wrap(ctx_cls, + "cells"); + readonly_wrapper<Context, decltype(&Context::nets), &Context::nets, wrap_context<NetMap &>>::def_wrap(ctx_cls, + "nets"); + WRAP_RANGE(Bel, conv_to_str<BelId>); + WRAP_RANGE(Wire, conv_to_str<WireId>); + WRAP_RANGE(AllPip, conv_to_str<PipId>); + WRAP_RANGE(Pip, conv_to_str<PipId>); + + WRAP_MAP_UPTR(CellMap, "IdCellMap"); + WRAP_MAP_UPTR(NetMap, "IdNetMap"); +} NEXTPNR_NAMESPACE_END -#endif +#endif // NO_PYTHON diff --git a/ecp5/bitstream.cc b/ecp5/bitstream.cc index 19ddb9f9..f1feba24 100644 --- a/ecp5/bitstream.cc +++ b/ecp5/bitstream.cc @@ -30,6 +30,7 @@ #include <fstream> #include <streambuf> +#include "io.h" #include "log.h" #include "util.h" @@ -182,12 +183,47 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex } } } + // Find bank voltages + std::unordered_map<int, IOVoltage> bankVcc; + std::unordered_map<int, bool> bankLvds; - // Set all bankref tiles to 3.3V (TODO) + for (auto &cell : ctx->cells) { + CellInfo *ci = cell.second.get(); + if (ci->bel != BelId() && ci->type == ctx->id("TRELLIS_IO")) { + int bank = ctx->getPioBelBank(ci->bel); + std::string dir = str_or_default(ci->params, ctx->id("DIR"), "INPUT"); + std::string iotype = str_or_default(ci->attrs, ctx->id("IO_TYPE"), "LVCMOS33"); + + if (dir != "INPUT") { + IOVoltage vcc = get_vccio(ioType_from_str(iotype)); + if (bankVcc.find(bank) != bankVcc.end()) { + // TODO: strong and weak constraints + if (bankVcc[bank] != vcc) { + log_error("Error processing '%s': incompatible IO voltages %s and %s on bank %d.", + cell.first.c_str(ctx), iovoltage_to_str(bankVcc[bank]).c_str(), + iovoltage_to_str(vcc).c_str(), bank); + } + } else { + bankVcc[bank] = vcc; + } + } + + if (iotype == "LVDS") + bankLvds[bank] = true; + } + } + + // Set all bankref tiles to appropriate VccIO for (const auto &tile : empty_chip.tiles) { std::string type = tile.second->info.type; if (type.find("BANKREF") != std::string::npos && type != "BANKREF8") { - cc.tiles[tile.first].add_enum("BANK.VCCIO", "3V3"); + int bank = std::stoi(type.substr(7)); + if (bankVcc.find(bank) != bankVcc.end()) + cc.tiles[tile.first].add_enum("BANK.VCCIO", iovoltage_to_str(bankVcc[bank])); + if (bankLvds[bank]) { + cc.tiles[tile.first].add_enum("BANK.DIFF_REF", "ON"); + cc.tiles[tile.first].add_enum("BANK.LVDSO", "ON"); + } } } @@ -235,6 +271,20 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex std::string pic_tile = get_pic_tile(ctx, empty_chip, bel); cc.tiles[pio_tile].add_enum(pio + ".BASE_TYPE", dir + "_" + iotype); cc.tiles[pic_tile].add_enum(pio + ".BASE_TYPE", dir + "_" + iotype); + if (is_differential(ioType_from_str(iotype))) { + // Explicitly disable other pair + std::string other; + if (pio == "PIOA") + other = "PIOB"; + else if (pio == "PIOC") + other = "PIOD"; + else + log_error("cannot place differential IO at location %s\n", pio.c_str()); + //cc.tiles[pio_tile].add_enum(other + ".BASE_TYPE", "_NONE_"); + //cc.tiles[pic_tile].add_enum(other + ".BASE_TYPE", "_NONE_"); + cc.tiles[pio_tile].add_enum(other + ".PULLMODE", "NONE"); + cc.tiles[pio_tile].add_enum(pio + ".PULLMODE", "NONE"); + } if (dir != "INPUT" && (ci->ports.find(ctx->id("T")) == ci->ports.end() || ci->ports.at(ctx->id("T")).net == nullptr)) { // Tie tristate low if unconnected for outputs or bidir @@ -247,7 +297,7 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex std::string cib_wirename = ctx->locInfo(cib_wire)->wire_data[cib_wire.index].name.get(); cc.tiles[cib_tile].add_enum("CIB." + cib_wirename + "MUX", "0"); } - if (dir == "INPUT") { + if (dir == "INPUT" && !is_differential(ioType_from_str(iotype))) { cc.tiles[pio_tile].add_enum(pio + ".HYSTERESIS", "ON"); } } else { diff --git a/ecp5/main.cc b/ecp5/main.cc index 5a4a900a..90096855 100644 --- a/ecp5/main.cc +++ b/ecp5/main.cc @@ -63,6 +63,7 @@ int main(int argc, char *argv[]) #ifndef NO_GUI options.add_options()("gui", "start gui"); #endif + options.add_options()("test", "check architecture database integrity"); options.add_options()("25k", "set device type to LFE5U-25F"); options.add_options()("45k", "set device type to LFE5U-45F"); @@ -148,6 +149,9 @@ int main(int argc, char *argv[]) if (vm.count("no-tmdriv")) ctx->timing_driven = false; + if (vm.count("test")) + ctx->archcheck(); + #ifndef NO_GUI if (vm.count("gui")) { Application a(argc, argv); |