diff options
author | David Shah <davey1576@gmail.com> | 2018-07-06 14:02:37 +0200 |
---|---|---|
committer | David Shah <davey1576@gmail.com> | 2018-07-11 10:41:36 +0200 |
commit | 83303bae5aec42ef411478dc2841b28aeecfd5e0 (patch) | |
tree | 3ffd8600738a30821cf75f6421aed85d56e59ad4 | |
parent | 074df03c593f03ba93ac19804c551e22a404d8d6 (diff) | |
download | nextpnr-83303bae5aec42ef411478dc2841b28aeecfd5e0.tar.gz nextpnr-83303bae5aec42ef411478dc2841b28aeecfd5e0.tar.bz2 nextpnr-83303bae5aec42ef411478dc2841b28aeecfd5e0.zip |
ecp5: Implementing (at least stubs) most of arch.cc
Signed-off-by: David Shah <davey1576@gmail.com>
-rw-r--r-- | ecp5/arch.cc | 289 | ||||
-rw-r--r-- | ecp5/arch.h | 24 | ||||
-rw-r--r-- | ecp5/arch_pybindings.h | 44 | ||||
-rw-r--r-- | ecp5/archdefs.h | 2 | ||||
-rw-r--r-- | ecp5/place_legaliser.cc | 26 | ||||
-rw-r--r-- | ecp5/place_legaliser.h | 31 |
6 files changed, 225 insertions, 191 deletions
diff --git a/ecp5/arch.cc b/ecp5/arch.cc index 41c73cf8..fe10d415 100644 --- a/ecp5/arch.cc +++ b/ecp5/arch.cc @@ -2,6 +2,7 @@ * nextpnr -- Next Generation Place and Route * * Copyright (C) 2018 Clifford Wolf <clifford@symbioticeda.com> + * 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 @@ -19,80 +20,41 @@ #include <algorithm> #include <cmath> +#include <cstring> #include "log.h" #include "nextpnr.h" #include "util.h" + NEXTPNR_NAMESPACE_BEGIN +static std::tuple<int, int, std::string> split_identifier_name(const std::string &name) +{ + size_t first_slash = name.find('/'); + NPNR_ASSERT(first_slash != std::string::npos); + size_t second_slash = name.find('/', first_slash + 1); + NPNR_ASSERT(second_slash != std::string::npos); + return std::make_tuple(std::stoi(name.substr(1, first_slash)), + std::stoi(name.substr(first_slash + 2, second_slash - first_slash)), + name.substr(second_slash + 1)); +}; + // ----------------------------------------------------------------------- IdString Arch::belTypeToId(BelType type) const { - if (type == TYPE_ICESTORM_LC) - return id("ICESTORM_LC"); - if (type == TYPE_ICESTORM_RAM) - return id("ICESTORM_RAM"); - if (type == TYPE_SB_IO) - return id("SB_IO"); - if (type == TYPE_SB_GB) - return id("SB_GB"); - if (type == TYPE_ICESTORM_PLL) - return id("ICESTORM_PLL"); - if (type == TYPE_SB_WARMBOOT) - return id("SB_WARMBOOT"); - if (type == TYPE_SB_MAC16) - return id("SB_MAC16"); - if (type == TYPE_ICESTORM_HFOSC) - return id("ICESTORM_HFOSC"); - if (type == TYPE_ICESTORM_LFOSC) - return id("ICESTORM_LFOSC"); - if (type == TYPE_SB_I2C) - return id("SB_I2C"); - if (type == TYPE_SB_SPI) - return id("SB_SPI"); - if (type == TYPE_IO_I3C) - return id("IO_I3C"); - if (type == TYPE_SB_LEDDA_IP) - return id("SB_LEDDA_IP"); - if (type == TYPE_SB_RGBA_DRV) - return id("SB_RGBA_DRV"); - if (type == TYPE_ICESTORM_SPRAM) - return id("ICESTORM_SPRAM"); + if (type == TYPE_TRELLIS_SLICE) + return id("TRELLIS_SLICE"); + if (type == TYPE_TRELLIS_IO) + return id("TRELLIS_IO"); return IdString(); } BelType Arch::belTypeFromId(IdString type) const { - if (type == id("ICESTORM_LC")) - return TYPE_ICESTORM_LC; - if (type == id("ICESTORM_RAM")) - return TYPE_ICESTORM_RAM; - if (type == id("SB_IO")) - return TYPE_SB_IO; - if (type == id("SB_GB")) - return TYPE_SB_GB; - if (type == id("ICESTORM_PLL")) - return TYPE_ICESTORM_PLL; - if (type == id("SB_WARMBOOT")) - return TYPE_SB_WARMBOOT; - if (type == id("SB_MAC16")) - return TYPE_SB_MAC16; - if (type == id("ICESTORM_HFOSC")) - return TYPE_ICESTORM_HFOSC; - if (type == id("ICESTORM_LFOSC")) - return TYPE_ICESTORM_LFOSC; - if (type == id("SB_I2C")) - return TYPE_SB_I2C; - if (type == id("SB_SPI")) - return TYPE_SB_SPI; - if (type == id("IO_I3C")) - return TYPE_IO_I3C; - if (type == id("SB_LEDDA_IP")) - return TYPE_SB_LEDDA_IP; - if (type == id("SB_RGBA_DRV")) - return TYPE_SB_RGBA_DRV; - if (type == id("ICESTORM_SPRAM")) - return TYPE_ICESTORM_SPRAM; + if (type == id("TRELLIS_SLICE")) + return TYPE_TRELLIS_SLICE; + if (type == id("TRELLIS_IO")) + return TYPE_TRELLIS_IO; return TYPE_NONE; } @@ -101,7 +63,9 @@ BelType Arch::belTypeFromId(IdString type) const void IdString::initialize_arch(const BaseCtx *ctx) { #define X(t) initialize_add(ctx, #t, PIN_##t); + #include "portpins.inc" + #undef X } @@ -134,102 +98,43 @@ Arch::Arch(ArchArgs args) : args(args) load_chipdb(); #endif -#ifdef ICE40_HX1K_ONLY - if (args.type == ArchArgs::HX1K) { - chip_info = get_chip_info(reinterpret_cast<const RelPtr<ChipInfoPOD> *>(chipdb_blob_1k)); + if (args.type == ArchArgs::LFE5U_25F) { + chip_info = get_chip_info(reinterpret_cast<const RelPtr<ChipInfoPOD> *>(chipdb_blob_25k)); + } else if (args.type == ArchArgs::LFE5U_45F) { + chip_info = get_chip_info(reinterpret_cast<const RelPtr<ChipInfoPOD> *>(chipdb_blob_45k)); + } else if (args.type == ArchArgs::LFE5U_85F) { + chip_info = get_chip_info(reinterpret_cast<const RelPtr<ChipInfoPOD> *>(chipdb_blob_85k)); } else { - log_error("Unsupported iCE40 chip type.\n"); - } -#else - if (args.type == ArchArgs::LP384) { - chip_info = get_chip_info(reinterpret_cast<const RelPtr<ChipInfoPOD> *>(chipdb_blob_384)); - } else if (args.type == ArchArgs::LP1K || args.type == ArchArgs::HX1K) { - chip_info = get_chip_info(reinterpret_cast<const RelPtr<ChipInfoPOD> *>(chipdb_blob_1k)); - } else if (args.type == ArchArgs::UP5K) { - chip_info = get_chip_info(reinterpret_cast<const RelPtr<ChipInfoPOD> *>(chipdb_blob_5k)); - } else if (args.type == ArchArgs::LP8K || args.type == ArchArgs::HX8K) { - chip_info = get_chip_info(reinterpret_cast<const RelPtr<ChipInfoPOD> *>(chipdb_blob_8k)); - } else { - log_error("Unsupported iCE40 chip type.\n"); - } -#endif - - package_info = nullptr; - for (int i = 0; i < chip_info->num_packages; i++) { - if (chip_info->packages_data[i].name.get() == args.package) { - package_info = &(chip_info->packages_data[i]); - break; - } + log_error("Unsupported ECP5 chip type.\n"); } - if (package_info == nullptr) - log_error("Unsupported package '%s'.\n", args.package.c_str()); - - bel_to_cell.resize(chip_info->num_bels); - wire_to_net.resize(chip_info->num_wires); - pip_to_net.resize(chip_info->num_pips); - switches_locked.resize(chip_info->num_switches); - - // Initialise regularly used IDStrings for performance - id_glb_buf_out = id("GLOBAL_BUFFER_OUTPUT"); - id_icestorm_lc = id("ICESTORM_LC"); - id_sb_io = id("SB_IO"); - id_sb_gb = id("SB_GB"); - id_cen = id("CEN"); - id_clk = id("CLK"); - id_sr = id("SR"); - id_i0 = id("I0"); - id_i1 = id("I1"); - id_i2 = id("I2"); - id_i3 = id("I3"); - id_dff_en = id("DFF_ENABLE"); - id_neg_clk = id("NEG_CLK"); } // ----------------------------------------------------------------------- std::string Arch::getChipName() { -#ifdef ICE40_HX1K_ONLY - if (args.type == ArchArgs::HX1K) { - return "Lattice LP1K"; - } else { - log_error("Unsupported iCE40 chip type.\n"); - } -#else - if (args.type == ArchArgs::LP384) { - return "Lattice LP384"; - } else if (args.type == ArchArgs::LP1K) { - return "Lattice LP1K"; - } else if (args.type == ArchArgs::HX1K) { - return "Lattice HX1K"; - } else if (args.type == ArchArgs::UP5K) { - return "Lattice UP5K"; - } else if (args.type == ArchArgs::LP8K) { - return "Lattice LP8K"; - } else if (args.type == ArchArgs::HX8K) { - return "Lattice HX8K"; + + if (args.type == ArchArgs::LFE5U_25F) { + return "Lattice LFE5U-25F"; + } else if (args.type == ArchArgs::LFE5U_45F) { + return "Lattice LFE5U-45F"; + } else if (args.type == ArchArgs::LFE5U_85F) { + return "Lattice LFE5U-85F"; } else { log_error("Unknown chip\n"); } -#endif } // ----------------------------------------------------------------------- IdString Arch::archArgsToId(ArchArgs args) const { - if (args.type == ArchArgs::LP384) - return id("lp384"); - if (args.type == ArchArgs::LP1K) - return id("lp1k"); - if (args.type == ArchArgs::HX1K) - return id("hx1k"); - if (args.type == ArchArgs::UP5K) - return id("up5k"); - if (args.type == ArchArgs::LP8K) - return id("lp8k"); - if (args.type == ArchArgs::HX8K) - return id("hx8k"); + if (args.type == ArchArgs::LFE5U_25F) + return id("lfe5u_25f"); + if (args.type == ArchArgs::LFE5U_45F) + return id("lfe5u_45f"); + if (args.type == ArchArgs::LFE5U_85F) + return id("lfe5u_85f"); return IdString(); } @@ -238,16 +143,23 @@ IdString Arch::archArgsToId(ArchArgs args) const BelId Arch::getBelByName(IdString name) const { BelId ret; - - if (bel_by_name.empty()) { - for (int i = 0; i < chip_info->num_bels; i++) - bel_by_name[id(chip_info->bel_data[i].name.get())] = i; - } - auto it = bel_by_name.find(name); if (it != bel_by_name.end()) - ret.index = it->second; - + return it->second; + + 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_bels; i++) { + if (std::strcmp(loci->bel_data[i].name.get(), basename.c_str()) == 0) { + ret.index = i; + break; + } + } + if (ret.index >= 0) + bel_by_name[name] = ret; return ret; } @@ -255,17 +167,10 @@ BelRange Arch::getBelsAtSameTile(BelId bel) const { BelRange br; NPNR_ASSERT(bel != BelId()); - // This requires Bels at the same tile are consecutive - int x = chip_info->bel_data[bel.index].x; - int y = chip_info->bel_data[bel.index].y; - int start = bel.index, end = bel.index; - while (start >= 0 && chip_info->bel_data[start].x == x && chip_info->bel_data[start].y == y) - start--; - start++; - br.b.cursor = start; - while (end < chip_info->num_bels && chip_info->bel_data[end].x == x && chip_info->bel_data[end].y == y) - end++; - br.e.cursor = end; + 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_index = 0; + br.e.cursor_index = locInfo(bel)->num_bels; return br; } @@ -275,11 +180,11 @@ WireId Arch::getWireBelPin(BelId bel, PortPin pin) const NPNR_ASSERT(bel != BelId()); - int num_bel_wires = chip_info->bel_data[bel.index].num_bel_wires; - const BelWirePOD *bel_wires = chip_info->bel_data[bel.index].bel_wires.get(); - + int num_bel_wires = locInfo(bel)->bel_data[bel.index].num_bel_wires; + const BelWirePOD *bel_wires = locInfo(bel)->bel_data[bel.index].bel_wires.get(); for (int i = 0; i < num_bel_wires; i++) if (bel_wires[i].port == pin) { + ret.location = bel.location + bel_wires[i].rel_wire_loc; ret.index = bel_wires[i].wire_index; break; } @@ -292,16 +197,23 @@ WireId Arch::getWireBelPin(BelId bel, PortPin pin) const WireId Arch::getWireByName(IdString name) const { WireId ret; - - if (wire_by_name.empty()) { - for (int i = 0; i < chip_info->num_wires; i++) - wire_by_name[id(chip_info->wire_data[i].name.get())] = i; - } - auto it = wire_by_name.find(name); if (it != wire_by_name.end()) - ret.index = it->second; - + return it->second; + + 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_wires; i++) { + if (std::strcmp(loci->wire_data[i].name.get(), basename.c_str()) == 0) { + ret.index = i; + break; + } + } + if (ret.index >= 0) + wire_by_name[name] = ret; return ret; } @@ -309,34 +221,35 @@ WireId Arch::getWireByName(IdString name) const PipId Arch::getPipByName(IdString name) const { - PipId ret; - - if (pip_by_name.empty()) { - for (int i = 0; i < chip_info->num_pips; i++) { - PipId pip; - pip.index = i; - pip_by_name[getPipName(pip)] = i; - } - } - auto it = pip_by_name.find(name); if (it != pip_by_name.end()) - ret.index = it->second; + return it->second; - return ret; + PipId ret; + Location loc; + std::string basename; + std::tie(loc.x, loc.y, basename) = split_identifier_name(name.str(this)); + const LocationTypePOD *loci = locInfo(ret); + for (int i = 0; i < loci->num_pips; i++) { + PipId curr; + curr.location = loc; + curr.index = i; + pip_by_name[getPipName(curr)] = curr; + } + return pip_by_name[name]; } IdString Arch::getPipName(PipId pip) const { NPNR_ASSERT(pip != PipId()); - int x = chip_info->pip_data[pip.index].x; - int y = chip_info->pip_data[pip.index].y; + int x = pip.location.x; + int y = pip.location.y; - std::string src_name = chip_info->wire_data[chip_info->pip_data[pip.index].src].name.get(); + std::string src_name = getWireName(getPipSrcWire(pip)).str(this); std::replace(src_name.begin(), src_name.end(), '/', '.'); - std::string dst_name = chip_info->wire_data[chip_info->pip_data[pip.index].dst].name.get(); + std::string dst_name = getWireName(getPipDstWire(pip)).str(this); std::replace(dst_name.begin(), dst_name.end(), '/', '.'); return id("X" + std::to_string(x) + "/Y" + std::to_string(y) + "/" + src_name + ".->." + dst_name); @@ -383,4 +296,10 @@ std::vector<GraphicElement> Arch::getPipGraphics(PipId pip) const return ret; }; +// ----------------------------------------------------------------------- + +bool Arch::isValidBelForCell(CellInfo *cell, BelId bel) const { return true; } + +bool Arch::isBelLocationValid(BelId bel) const { return true; } + NEXTPNR_NAMESPACE_END diff --git a/ecp5/arch.h b/ecp5/arch.h index 85a3e44c..91e9fdcd 100644 --- a/ecp5/arch.h +++ b/ecp5/arch.h @@ -2,6 +2,7 @@ * nextpnr -- Next Generation Place and Route * * Copyright (C) 2018 Clifford Wolf <clifford@symbioticeda.com> + * 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 @@ -21,6 +22,8 @@ #error Include "arch.h" via "nextpnr.h" only. #endif +#include <sstream> + NEXTPNR_NAMESPACE_BEGIN /**** Everything in this section must be kept in sync with chipdb.py ****/ @@ -340,9 +343,9 @@ struct Arch : BaseCtx { const ChipInfoPOD *chip_info; - mutable std::unordered_map<IdString, int> bel_by_name; - mutable std::unordered_map<IdString, int> wire_by_name; - mutable std::unordered_map<IdString, int> pip_by_name; + mutable std::unordered_map<IdString, BelId> bel_by_name; + mutable std::unordered_map<IdString, WireId> wire_by_name; + mutable std::unordered_map<IdString, PipId> pip_by_name; std::unordered_map<BelId, IdString> bel_to_cell; std::unordered_map<WireId, IdString> wire_to_net; @@ -375,7 +378,9 @@ struct Arch : BaseCtx IdString getBelName(BelId bel) const { NPNR_ASSERT(bel != BelId()); - return id(locInfo(bel)->bel_data[bel.index].name.get()); + std::stringstream name; + name << "X" << bel.location.x << "/Y" << bel.location.y << "/" << locInfo(bel)->bel_data[bel.index].name.get(); + return id(name.str()); } uint32_t getBelChecksum(BelId bel) const { return bel.index; } @@ -491,7 +496,11 @@ struct Arch : BaseCtx IdString getWireName(WireId wire) const { NPNR_ASSERT(wire != WireId()); - return id(locInfo(wire)->wire_data[wire.index].name.get()); + + std::stringstream name; + name << "X" << wire.location.x << "/Y" << wire.location.y << "/" + << locInfo(wire)->wire_data[wire.index].name.get(); + return id(name.str()); } uint32_t getWireChecksum(WireId wire) const { return wire.index; } @@ -724,6 +733,11 @@ struct Arch : BaseCtx bool isClockPort(const CellInfo *cell, IdString port) const; // Return true if a port is a net bool isGlobalNet(const NetInfo *net) const; + + // ------------------------------------------------- + // Placement validity checks + bool isValidBelForCell(CellInfo *cell, BelId bel) const; + bool isBelLocationValid(BelId bel) const; }; NEXTPNR_NAMESPACE_END diff --git a/ecp5/arch_pybindings.h b/ecp5/arch_pybindings.h index f7f07529..a5044f29 100644 --- a/ecp5/arch_pybindings.h +++ b/ecp5/arch_pybindings.h @@ -26,6 +26,50 @@ NEXTPNR_NAMESPACE_BEGIN +namespace PythonConversion { + +template <> struct string_converter<BelId> +{ + BelId from_str(Context *ctx, std::string name) { return ctx->getBelByName(ctx->id(name)); } + + std::string to_str(Context *ctx, BelId id) + { + if (id == BelId()) + throw bad_wrap(); + return ctx->getBelName(id).str(ctx); + } +}; + +template <> struct string_converter<BelType> +{ + BelType from_str(Context *ctx, std::string name) { return ctx->belTypeFromId(ctx->id(name)); } + + std::string to_str(Context *ctx, BelType typ) { return ctx->belTypeToId(typ).str(ctx); } +}; + +template <> struct string_converter<WireId> +{ + WireId from_str(Context *ctx, std::string name) { return ctx->getWireByName(ctx->id(name)); } + + std::string to_str(Context *ctx, WireId id) { return ctx->getWireName(id).str(ctx); } +}; + +template <> struct string_converter<PipId> +{ + PipId from_str(Context *ctx, std::string name) { return ctx->getPipByName(ctx->id(name)); } + + std::string to_str(Context *ctx, PipId id) { return ctx->getPipName(id).str(ctx); } +}; + +template <> struct string_converter<PortPin> +{ + PortPin from_str(Context *ctx, std::string name) { return ctx->portPinFromId(ctx->id(name)); } + + std::string to_str(Context *ctx, PortPin id) { return ctx->portPinToId(id).str(ctx); } +}; + +} // namespace PythonConversion + NEXTPNR_NAMESPACE_END #endif #endif diff --git a/ecp5/archdefs.h b/ecp5/archdefs.h index f913e445..b05ac22c 100644 --- a/ecp5/archdefs.h +++ b/ecp5/archdefs.h @@ -74,7 +74,7 @@ struct Location bool operator!=(const Location &other) const { return x != other.x || y == other.y; } }; -Location operator+(const Location &a, const Location &b) { return Location(a.x + b.x, a.y + b.y); } +inline Location operator+(const Location &a, const Location &b) { return Location(a.x + b.x, a.y + b.y); } struct BelId { diff --git a/ecp5/place_legaliser.cc b/ecp5/place_legaliser.cc new file mode 100644 index 00000000..0d23f15b --- /dev/null +++ b/ecp5/place_legaliser.cc @@ -0,0 +1,26 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * 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 + * 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 "place_legaliser.h" + +NEXTPNR_NAMESPACE_BEGIN + +bool legalise_design(Context *ctx) { return true; } + +NEXTPNR_NAMESPACE_END diff --git a/ecp5/place_legaliser.h b/ecp5/place_legaliser.h new file mode 100644 index 00000000..5f4df6aa --- /dev/null +++ b/ecp5/place_legaliser.h @@ -0,0 +1,31 @@ +/* + * nextpnr -- Next Generation Place and Route + * + * 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 + * 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 PLACE_LEGALISER_H +#define PLACE_LEGALISER_H + +#include "nextpnr.h" + +NEXTPNR_NAMESPACE_BEGIN + +bool legalise_design(Context *ctx); + +NEXTPNR_NAMESPACE_END + +#endif |