aboutsummaryrefslogtreecommitdiffstats
path: root/ecp5
diff options
context:
space:
mode:
authorDavid Shah <davey1576@gmail.com>2018-07-06 12:15:07 +0200
committerDavid Shah <davey1576@gmail.com>2018-07-11 10:41:36 +0200
commit7862d1b84b9f770a97f1650cf4a1eb2e02b6389f (patch)
treea8c527d045962f298335a03275d908d6bfcfe67f /ecp5
parentc4af52dd5b3830905e2b9e8f7135f886882841ba (diff)
downloadnextpnr-7862d1b84b9f770a97f1650cf4a1eb2e02b6389f.tar.gz
nextpnr-7862d1b84b9f770a97f1650cf4a1eb2e02b6389f.tar.bz2
nextpnr-7862d1b84b9f770a97f1650cf4a1eb2e02b6389f.zip
ecp5: Implementing core arch.h functions
Signed-off-by: David Shah <davey1576@gmail.com>
Diffstat (limited to 'ecp5')
-rw-r--r--ecp5/arch.cc386
-rw-r--r--ecp5/arch.h199
-rw-r--r--ecp5/arch_pybindings.cc32
-rw-r--r--ecp5/arch_pybindings.h31
-rw-r--r--ecp5/archdefs.h46
-rw-r--r--ecp5/main.cc139
6 files changed, 746 insertions, 87 deletions
diff --git a/ecp5/arch.cc b/ecp5/arch.cc
new file mode 100644
index 00000000..41c73cf8
--- /dev/null
+++ b/ecp5/arch.cc
@@ -0,0 +1,386 @@
+/*
+ * nextpnr -- Next Generation Place and Route
+ *
+ * Copyright (C) 2018 Clifford Wolf <clifford@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 <algorithm>
+#include <cmath>
+#include "log.h"
+#include "nextpnr.h"
+#include "util.h"
+NEXTPNR_NAMESPACE_BEGIN
+
+// -----------------------------------------------------------------------
+
+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");
+ 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;
+ return TYPE_NONE;
+}
+
+// -----------------------------------------------------------------------
+
+void IdString::initialize_arch(const BaseCtx *ctx)
+{
+#define X(t) initialize_add(ctx, #t, PIN_##t);
+#include "portpins.inc"
+#undef X
+}
+
+IdString Arch::portPinToId(PortPin type) const
+{
+ IdString ret;
+ if (type > 0 && type < PIN_MAXIDX)
+ ret.index = type;
+ return ret;
+}
+
+PortPin Arch::portPinFromId(IdString type) const
+{
+ if (type.index > 0 && type.index < PIN_MAXIDX)
+ return PortPin(type.index);
+ return PIN_NONE;
+}
+
+// -----------------------------------------------------------------------
+
+static const ChipInfoPOD *get_chip_info(const RelPtr<ChipInfoPOD> *ptr) { return ptr->get(); }
+
+#if defined(_MSC_VER)
+void load_chipdb();
+#endif
+
+Arch::Arch(ArchArgs args) : args(args)
+{
+#if defined(_MSC_VER)
+ 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));
+ } 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;
+ }
+ }
+ 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";
+ } 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");
+ return IdString();
+}
+
+// -----------------------------------------------------------------------
+
+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 ret;
+}
+
+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;
+ return br;
+}
+
+WireId Arch::getWireBelPin(BelId bel, PortPin pin) const
+{
+ WireId ret;
+
+ 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();
+
+ for (int i = 0; i < num_bel_wires; i++)
+ if (bel_wires[i].port == pin) {
+ ret.index = bel_wires[i].wire_index;
+ break;
+ }
+
+ return ret;
+}
+
+// -----------------------------------------------------------------------
+
+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 ret;
+}
+
+// -----------------------------------------------------------------------
+
+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 ret;
+}
+
+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;
+
+ std::string src_name = chip_info->wire_data[chip_info->pip_data[pip.index].src].name.get();
+ 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::replace(dst_name.begin(), dst_name.end(), '/', '.');
+
+ return id("X" + std::to_string(x) + "/Y" + std::to_string(y) + "/" + src_name + ".->." + dst_name);
+}
+
+// -----------------------------------------------------------------------
+
+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 {}
+
+delay_t Arch::estimateDelay(WireId src, WireId dst) const { return 1; }
+
+// -----------------------------------------------------------------------
+
+std::vector<GraphicElement> Arch::getFrameGraphics() const
+{
+ std::vector<GraphicElement> ret;
+
+ return ret;
+}
+
+std::vector<GraphicElement> Arch::getBelGraphics(BelId bel) const
+{
+ std::vector<GraphicElement> ret;
+
+ return ret;
+}
+
+std::vector<GraphicElement> Arch::getWireGraphics(WireId wire) const
+{
+ std::vector<GraphicElement> ret;
+ // FIXME
+ return ret;
+}
+
+std::vector<GraphicElement> Arch::getPipGraphics(PipId pip) const
+{
+ std::vector<GraphicElement> ret;
+ // FIXME
+ return ret;
+};
+
+NEXTPNR_NAMESPACE_END
diff --git a/ecp5/arch.h b/ecp5/arch.h
index 98c4cd76..85a3e44c 100644
--- a/ecp5/arch.h
+++ b/ecp5/arch.h
@@ -44,7 +44,7 @@ template <typename T> struct RelPtr
};
NPNR_PACKED_STRUCT(struct BelWirePOD {
- Location rel_wire_loc;
+ LocationPOD rel_wire_loc;
int32_t wire_index;
PortPin port;
});
@@ -59,23 +59,23 @@ NPNR_PACKED_STRUCT(struct BelInfoPOD {
});
NPNR_PACKED_STRUCT(struct BelPortPOD {
- Location rel_bel_loc;
+ LocationPOD rel_bel_loc;
int32_t bel_index;
PortPin port;
});
NPNR_PACKED_STRUCT(struct PipInfoPOD {
- Location rel_src_loc, rel_dst_loc;
+ LocationPOD rel_src_loc, rel_dst_loc;
int32_t src_idx, dst_idx;
int32_t delay;
- Location rel_tile_loc;
+ LocationPOD rel_tile_loc;
int16_t tile_type;
int8_t pip_type;
int8_t padding_0;
});
NPNR_PACKED_STRUCT(struct PipLocatorPOD {
- Location rel_loc;
+ LocationPOD rel_loc;
int32_t index;
});
@@ -98,21 +98,20 @@ NPNR_PACKED_STRUCT(struct LocationTypePOD {
NPNR_PACKED_STRUCT(struct ChipInfoPOD {
int32_t width, height;
+ int32_t num_tiles;
int32_t num_location_types;
RelPtr<LocationTypePOD> locations;
RelPtr<int32_t> location_type;
});
#if defined(_MSC_VER)
-extern const char *chipdb_blob_384;
-extern const char *chipdb_blob_1k;
-extern const char *chipdb_blob_5k;
-extern const char *chipdb_blob_8k;
+extern const char *chipdb_blob_25k;
+extern const char *chipdb_blob_45k;
+extern const char *chipdb_blob_85k;
#else
-extern const char chipdb_blob_384[];
-extern const char chipdb_blob_1k[];
-extern const char chipdb_blob_5k[];
-extern const char chipdb_blob_8k[];
+extern const char chipdb_blob_25k[];
+extern const char chipdb_blob_45k[];
+extern const char chipdb_blob_85k[];
#endif
/************************ End of chipdb section. ************************/
@@ -126,7 +125,8 @@ struct BelIterator
BelIterator operator++()
{
cursor_index++;
- while (cursor_index >= ci->locations[ci->location_type[cursor_tile]]->num_bels) {
+ while (cursor_tile < chip->num_tiles &&
+ cursor_index >= chip->locations[chip->location_type[cursor_tile]].num_bels) {
cursor_index = 0;
cursor_tile++;
}
@@ -135,7 +135,7 @@ struct BelIterator
BelIterator operator++(int)
{
BelIterator prior(*this);
- cursor++;
+ ++(*this);
return prior;
}
@@ -171,7 +171,7 @@ struct BelRange
struct BelPinIterator
{
const BelPortPOD *ptr = nullptr;
- const Location wire_loc;
+ Location wire_loc;
void operator++() { ptr++; }
bool operator!=(const BelPinIterator &other) const { return ptr != other.ptr; }
@@ -203,7 +203,8 @@ struct WireIterator
WireIterator operator++()
{
cursor_index++;
- while (cursor_index >= ci->locations[ci->location_type[cursor_tile]]->num_wires) {
+ while (cursor_tile < chip->num_tiles &&
+ cursor_index >= chip->locations[chip->location_type[cursor_tile]].num_wires) {
cursor_index = 0;
cursor_tile++;
}
@@ -212,7 +213,7 @@ struct WireIterator
WireIterator operator++(int)
{
WireIterator prior(*this);
- cursor++;
+ ++(*this);
return prior;
}
@@ -254,7 +255,8 @@ struct AllPipIterator
AllPipIterator operator++()
{
cursor_index++;
- while (cursor_index >= ci->locations[ci->location_type[cursor_tile]]->num_pips) {
+ while (cursor_tile < chip->num_tiles &&
+ cursor_index >= chip->locations[chip->location_type[cursor_tile]].num_pips) {
cursor_index = 0;
cursor_tile++;
}
@@ -262,8 +264,8 @@ struct AllPipIterator
}
AllPipIterator operator++(int)
{
- WireIterator prior(*this);
- cursor++;
+ AllPipIterator prior(*this);
+ ++(*this);
return prior;
}
@@ -309,7 +311,7 @@ struct PipIterator
{
PipId ret;
ret.index = cursor->index;
- ret.location = wire_loc + cursor->location;
+ ret.location = wire_loc + cursor->rel_loc;
return ret;
}
};
@@ -337,7 +339,6 @@ struct ArchArgs
struct Arch : BaseCtx
{
const ChipInfoPOD *chip_info;
- const PackageInfoPOD *package_info;
mutable std::unordered_map<IdString, int> bel_by_name;
mutable std::unordered_map<IdString, int> wire_by_name;
@@ -366,10 +367,15 @@ struct Arch : BaseCtx
BelId getBelByName(IdString name) const;
+ template <typename Id> const LocationTypePOD *locInfo(Id &id) const
+ {
+ return &(chip_info->locations[chip_info->location_type[id.location.y * chip_info->width + id.location.x]]);
+ }
+
IdString getBelName(BelId bel) const
{
NPNR_ASSERT(bel != BelId());
- return id(chip_info->bel_data[bel.index].name.get());
+ return id(locInfo(bel)->bel_data[bel.index].name.get());
}
uint32_t getBelChecksum(BelId bel) const { return bel.index; }
@@ -386,35 +392,46 @@ struct Arch : BaseCtx
void unbindBel(BelId bel)
{
NPNR_ASSERT(bel != BelId());
- NPNR_ASSERT(bel_to_cell[bel.index] != IdString());
- cells[bel_to_cell[bel.index]]->bel = BelId();
- cells[bel_to_cell[bel.index]]->belStrength = STRENGTH_NONE;
- bel_to_cell[bel.index] = IdString();
+ NPNR_ASSERT(bel_to_cell[bel] != IdString());
+ cells[bel_to_cell[bel]]->bel = BelId();
+ cells[bel_to_cell[bel]]->belStrength = STRENGTH_NONE;
+ bel_to_cell[bel] = IdString();
}
bool checkBelAvail(BelId bel) const
{
NPNR_ASSERT(bel != BelId());
- return bel_to_cell[bel.index] == IdString();
+ return bel_to_cell.find(bel) == bel_to_cell.end() || bel_to_cell.at(bel) == IdString();
}
IdString getBoundBelCell(BelId bel) const
{
NPNR_ASSERT(bel != BelId());
- return bel_to_cell.at(bel);
+ if (bel_to_cell.find(bel) == bel_to_cell.end())
+ return IdString();
+ else
+ return bel_to_cell.at(bel);
}
IdString getConflictingBelCell(BelId bel) const
{
NPNR_ASSERT(bel != BelId());
- return bel_to_cell.at(bel);
+ if (bel_to_cell.find(bel) == bel_to_cell.end())
+ return IdString();
+ else
+ return bel_to_cell.at(bel);
}
BelRange getBels() const
{
BelRange range;
- range.b.cursor = 0;
- range.e.cursor = chip_info->num_bels;
+ range.b.cursor_tile = 0;
+ range.b.cursor_index = -1;
+ range.b.chip = chip_info;
+ ++range.b; //-1 and then ++ deals with the case of no Bels in the first tile
+ range.e.cursor_tile = chip_info->width * chip_info->height;
+ range.e.cursor_index = 0;
+ range.e.chip = chip_info;
return range;
}
@@ -437,7 +454,7 @@ struct Arch : BaseCtx
BelType getBelType(BelId bel) const
{
NPNR_ASSERT(bel != BelId());
- return chip_info->bel_data[bel.index].type;
+ return locInfo(bel)->bel_data[bel.index].type;
}
WireId getWireBelPin(BelId bel, PortPin pin) const;
@@ -447,9 +464,10 @@ struct Arch : BaseCtx
BelPin ret;
NPNR_ASSERT(wire != WireId());
- if (chip_info->wire_data[wire.index].bel_uphill.bel_index >= 0) {
- ret.bel.index = chip_info->wire_data[wire.index].bel_uphill.bel_index;
- ret.pin = chip_info->wire_data[wire.index].bel_uphill.port;
+ if (locInfo(wire)->wire_data[wire.index].bel_uphill.bel_index >= 0) {
+ ret.bel.index = locInfo(wire)->wire_data[wire.index].bel_uphill.bel_index;
+ ret.bel.location = wire.location + locInfo(wire)->wire_data[wire.index].bel_uphill.rel_bel_loc;
+ ret.pin = locInfo(wire)->wire_data[wire.index].bel_uphill.port;
}
return ret;
@@ -459,8 +477,10 @@ struct Arch : BaseCtx
{
BelPinRange range;
NPNR_ASSERT(wire != WireId());
- range.b.ptr = chip_info->wire_data[wire.index].bels_downhill.get();
- range.e.ptr = range.b.ptr + chip_info->wire_data[wire.index].num_bels_downhill;
+ range.b.ptr = locInfo(wire)->wire_data[wire.index].bels_downhill.get();
+ range.b.wire_loc = wire.location;
+ range.e.ptr = range.b.ptr + locInfo(wire)->wire_data[wire.index].num_bels_downhill;
+ range.e.wire_loc = wire.location;
return range;
}
@@ -471,7 +491,7 @@ struct Arch : BaseCtx
IdString getWireName(WireId wire) const
{
NPNR_ASSERT(wire != WireId());
- return id(chip_info->wire_data[wire.index].name.get());
+ return id(locInfo(wire)->wire_data[wire.index].name.get());
}
uint32_t getWireChecksum(WireId wire) const { return wire.index; }
@@ -479,8 +499,8 @@ struct Arch : BaseCtx
void bindWire(WireId wire, IdString net, PlaceStrength strength)
{
NPNR_ASSERT(wire != WireId());
- NPNR_ASSERT(wire_to_net[wire.index] == IdString());
- wire_to_net[wire.index] = net;
+ NPNR_ASSERT(wire_to_net[wire] == IdString());
+ wire_to_net[wire] = net;
nets[net]->wires[wire].pip = PipId();
nets[net]->wires[wire].strength = strength;
}
@@ -488,45 +508,55 @@ struct Arch : BaseCtx
void unbindWire(WireId wire)
{
NPNR_ASSERT(wire != WireId());
- NPNR_ASSERT(wire_to_net[wire.index] != IdString());
+ NPNR_ASSERT(wire_to_net[wire] != IdString());
- auto &net_wires = nets[wire_to_net[wire.index]]->wires;
+ auto &net_wires = nets[wire_to_net[wire]]->wires;
auto it = net_wires.find(wire);
NPNR_ASSERT(it != net_wires.end());
auto pip = it->second.pip;
if (pip != PipId()) {
- pip_to_net[pip.index] = IdString();
- switches_locked[chip_info->pip_data[pip.index].switch_index] = IdString();
+ pip_to_net[pip] = IdString();
}
net_wires.erase(it);
- wire_to_net[wire.index] = IdString();
+ wire_to_net[wire] = IdString();
}
bool checkWireAvail(WireId wire) const
{
NPNR_ASSERT(wire != WireId());
- return wire_to_net[wire.index] == IdString();
+ return wire_to_net.find(wire) == wire_to_net.end() || wire_to_net.at(wire) == IdString();
}
IdString getBoundWireNet(WireId wire) const
{
NPNR_ASSERT(wire != WireId());
- return wire_to_net[wire.index];
+ if (wire_to_net.find(wire) == wire_to_net.end())
+ return IdString();
+ else
+ return wire_to_net.at(wire);
}
IdString getConflictingWireNet(WireId wire) const
{
NPNR_ASSERT(wire != WireId());
- return wire_to_net[wire.index];
+ if (wire_to_net.find(wire) == wire_to_net.end())
+ return IdString();
+ else
+ return wire_to_net.at(wire);
}
WireRange getWires() const
{
WireRange range;
- range.b.cursor = 0;
- range.e.cursor = chip_info->num_wires;
+ range.b.cursor_tile = 0;
+ range.b.cursor_index = -1;
+ range.b.chip = chip_info;
+ ++range.b; //-1 and then ++ deals with the case of no wries in the first tile
+ range.e.cursor_tile = chip_info->width * chip_info->height;
+ range.e.cursor_index = 0;
+ range.e.chip = chip_info;
return range;
}
@@ -540,16 +570,15 @@ struct Arch : BaseCtx
void bindPip(PipId pip, IdString net, PlaceStrength strength)
{
NPNR_ASSERT(pip != PipId());
- NPNR_ASSERT(pip_to_net[pip.index] == IdString());
- NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] == IdString());
+ NPNR_ASSERT(pip_to_net[pip] == IdString());
- pip_to_net[pip.index] = net;
- switches_locked[chip_info->pip_data[pip.index].switch_index] = net;
+ pip_to_net[pip] = net;
WireId dst;
- dst.index = chip_info->pip_data[pip.index].dst;
- NPNR_ASSERT(wire_to_net[dst.index] == IdString());
- wire_to_net[dst.index] = net;
+ dst.index = locInfo(pip)->pip_data[pip.index].dst_idx;
+ dst.location = pip.location + locInfo(pip)->pip_data[pip.index].rel_dst_loc;
+ NPNR_ASSERT(wire_to_net[dst] == IdString());
+ wire_to_net[dst] = net;
nets[net]->wires[dst].pip = pip;
nets[net]->wires[dst].strength = strength;
}
@@ -557,42 +586,52 @@ struct Arch : BaseCtx
void unbindPip(PipId pip)
{
NPNR_ASSERT(pip != PipId());
- NPNR_ASSERT(pip_to_net[pip.index] != IdString());
- NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] != IdString());
+ NPNR_ASSERT(pip_to_net[pip] != IdString());
WireId dst;
- dst.index = chip_info->pip_data[pip.index].dst;
- NPNR_ASSERT(wire_to_net[dst.index] != IdString());
- wire_to_net[dst.index] = IdString();
- nets[pip_to_net[pip.index]]->wires.erase(dst);
+ dst.index = locInfo(pip)->pip_data[pip.index].dst_idx;
+ dst.location = pip.location + locInfo(pip)->pip_data[pip.index].rel_dst_loc;
+ NPNR_ASSERT(wire_to_net[dst] != IdString());
+ wire_to_net[dst] = IdString();
+ nets[pip_to_net[pip]]->wires.erase(dst);
- pip_to_net[pip.index] = IdString();
- switches_locked[chip_info->pip_data[pip.index].switch_index] = IdString();
+ pip_to_net[pip] = IdString();
}
bool checkPipAvail(PipId pip) const
{
NPNR_ASSERT(pip != PipId());
- return switches_locked[chip_info->pip_data[pip.index].switch_index] == IdString();
+ return pip_to_net.find(pip) == pip_to_net.end() || pip_to_net.at(pip) == IdString();
}
IdString getBoundPipNet(PipId pip) const
{
NPNR_ASSERT(pip != PipId());
- return pip_to_net[pip.index];
+ if (pip_to_net.find(pip) == pip_to_net.end())
+ return IdString();
+ else
+ return pip_to_net.at(pip);
}
IdString getConflictingPipNet(PipId pip) const
{
NPNR_ASSERT(pip != PipId());
- return switches_locked[chip_info->pip_data[pip.index].switch_index];
+ if (pip_to_net.find(pip) == pip_to_net.end())
+ return IdString();
+ else
+ return pip_to_net.at(pip);
}
AllPipRange getPips() const
{
AllPipRange range;
- range.b.cursor = 0;
- range.e.cursor = chip_info->num_pips;
+ range.b.cursor_tile = 0;
+ range.b.cursor_index = -1;
+ range.b.chip = chip_info;
+ ++range.b; //-1 and then ++ deals with the case of no wries in the first tile
+ range.e.cursor_tile = chip_info->width * chip_info->height;
+ range.e.cursor_index = 0;
+ range.e.chip = chip_info;
return range;
}
@@ -600,7 +639,8 @@ struct Arch : BaseCtx
{
WireId wire;
NPNR_ASSERT(pip != PipId());
- wire.index = chip_info->pip_data[pip.index].src;
+ wire.index = locInfo(pip)->pip_data[pip.index].src_idx;
+ wire.location = pip.location + locInfo(pip)->pip_data[pip.index].rel_src_loc;
return wire;
}
@@ -608,7 +648,8 @@ struct Arch : BaseCtx
{
WireId wire;
NPNR_ASSERT(pip != PipId());
- wire.index = chip_info->pip_data[pip.index].dst;
+ wire.index = locInfo(pip)->pip_data[pip.index].dst_idx;
+ wire.location = pip.location + locInfo(pip)->pip_data[pip.index].rel_dst_loc;
return wire;
}
@@ -616,7 +657,7 @@ struct Arch : BaseCtx
{
DelayInfo delay;
NPNR_ASSERT(pip != PipId());
- delay.delay = chip_info->pip_data[pip.index].delay;
+ delay.delay = locInfo(pip)->pip_data[pip.index].delay;
return delay;
}
@@ -624,8 +665,8 @@ struct Arch : BaseCtx
{
PipRange range;
NPNR_ASSERT(wire != WireId());
- range.b.cursor = chip_info->wire_data[wire.index].pips_downhill.get();
- range.e.cursor = range.b.cursor + chip_info->wire_data[wire.index].num_downhill;
+ range.b.cursor = locInfo(wire)->wire_data[wire.index].pips_downhill.get();
+ range.e.cursor = range.b.cursor + locInfo(wire)->wire_data[wire.index].num_downhill;
return range;
}
@@ -633,8 +674,8 @@ struct Arch : BaseCtx
{
PipRange range;
NPNR_ASSERT(wire != WireId());
- range.b.cursor = chip_info->wire_data[wire.index].pips_uphill.get();
- range.e.cursor = range.b.cursor + chip_info->wire_data[wire.index].num_uphill;
+ range.b.cursor = locInfo(wire)->wire_data[wire.index].pips_uphill.get();
+ range.e.cursor = range.b.cursor + locInfo(wire)->wire_data[wire.index].num_uphill;
return range;
}
diff --git a/ecp5/arch_pybindings.cc b/ecp5/arch_pybindings.cc
new file mode 100644
index 00000000..8310c3a1
--- /dev/null
+++ b/ecp5/arch_pybindings.cc
@@ -0,0 +1,32 @@
+/*
+ * nextpnr -- Next Generation Place and Route
+ *
+ * Copyright (C) 2018 Clifford Wolf <clifford@symbioticeda.com>
+ * Copyright (C) 2018 David Shah <dave@ds0.me>
+ *
+ * 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 NO_PYTHON
+
+#include "nextpnr.h"
+#include "pybindings.h"
+
+NEXTPNR_NAMESPACE_BEGIN
+
+void arch_wrap_python() {}
+
+NEXTPNR_NAMESPACE_END
+
+#endif
diff --git a/ecp5/arch_pybindings.h b/ecp5/arch_pybindings.h
new file mode 100644
index 00000000..f7f07529
--- /dev/null
+++ b/ecp5/arch_pybindings.h
@@ -0,0 +1,31 @@
+/*
+ * 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
+ * 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 ARCH_PYBINDINGS_H
+#define ARCH_PYBINDINGS_H
+#ifndef NO_PYTHON
+
+#include "nextpnr.h"
+#include "pybindings.h"
+
+NEXTPNR_NAMESPACE_BEGIN
+
+NEXTPNR_NAMESPACE_END
+#endif
+#endif
diff --git a/ecp5/archdefs.h b/ecp5/archdefs.h
index 0af48753..f913e445 100644
--- a/ecp5/archdefs.h
+++ b/ecp5/archdefs.h
@@ -60,13 +60,21 @@ enum PortPin : int32_t
PIN_MAXIDX
};
-NPNR_PACKED_STRUCT(struct Location {
+NPNR_PACKED_STRUCT(struct LocationPOD { int16_t x, y; });
+
+struct Location
+{
int16_t x = -1, y = -1;
+ Location() : x(-1), y(-1){};
+ Location(int16_t x, int16_t y) : x(x), y(y){};
+ Location(const LocationPOD &pod) : x(pod.x), y(pod.y){};
+ Location(const Location &loc) : x(loc.x), y(loc.y){};
+
bool operator==(const Location &other) const { return x == other.x && y == other.y; }
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};}
+Location operator+(const Location &a, const Location &b) { return Location(a.x + b.x, a.y + b.y); }
struct BelId
{
@@ -91,29 +99,51 @@ struct PipId
Location location;
int32_t index = -1;
- bool operator==(const WireId &other) const { return index == other.index && location == other.location; }
- bool operator!=(const WireId &other) const { return index != other.index || location != other.location; }
+ bool operator==(const PipId &other) const { return index == other.index && location == other.location; }
+ bool operator!=(const PipId &other) const { return index != other.index || location != other.location; }
};
NEXTPNR_NAMESPACE_END
namespace std {
+template <> struct hash<NEXTPNR_NAMESPACE_PREFIX Location>
+{
+ std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX Location &loc) const noexcept
+ {
+ std::size_t seed = std::hash<int>()(loc.x);
+ seed ^= std::hash<int>()(loc.y) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
+ return seed;
+ }
+};
+
template <> struct hash<NEXTPNR_NAMESPACE_PREFIX BelId>
{
- std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX BelId &bel) const noexcept { return hash<int>()(bel.index); }
+ std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX BelId &bel) const noexcept
+ {
+ std::size_t seed = std::hash<NEXTPNR_NAMESPACE_PREFIX Location>()(bel.location);
+ seed ^= std::hash<int>()(bel.index) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
+ return seed;
+ }
};
template <> struct hash<NEXTPNR_NAMESPACE_PREFIX WireId>
{
std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX WireId &wire) const noexcept
{
- return hash<int>()(wire.index);
+ std::size_t seed = std::hash<NEXTPNR_NAMESPACE_PREFIX Location>()(wire.location);
+ seed ^= std::hash<int>()(wire.index) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
+ return seed;
}
};
template <> struct hash<NEXTPNR_NAMESPACE_PREFIX PipId>
{
- std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX PipId &pip) const noexcept { return hash<int>()(pip.index); }
+ std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX PipId &pip) const noexcept
+ {
+ std::size_t seed = std::hash<NEXTPNR_NAMESPACE_PREFIX Location>()(pip.location);
+ seed ^= std::hash<int>()(pip.index) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
+ return seed;
+ }
};
template <> struct hash<NEXTPNR_NAMESPACE_PREFIX BelType> : hash<int>
diff --git a/ecp5/main.cc b/ecp5/main.cc
new file mode 100644
index 00000000..d025d8d4
--- /dev/null
+++ b/ecp5/main.cc
@@ -0,0 +1,139 @@
+/*
+ * nextpnr -- Next Generation Place and Route
+ *
+ * Copyright (C) 2018 Clifford Wolf <clifford@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.
+ *
+ */
+
+#ifdef MAIN_EXECUTABLE
+
+#ifndef NO_GUI
+#include <QApplication>
+#include "application.h"
+#include "mainwindow.h"
+#endif
+#ifndef NO_PYTHON
+#include "pybindings.h"
+#endif
+#include <boost/filesystem/convenience.hpp>
+#include <boost/program_options.hpp>
+#include <iostream>
+#include "log.h"
+#include "nextpnr.h"
+#include "version.h"
+
+USING_NEXTPNR_NAMESPACE
+
+int main(int argc, char *argv[])
+{
+ try {
+
+ namespace po = boost::program_options;
+ int rc = 0;
+
+ log_files.push_back(stdout);
+
+ po::options_description options("Allowed options");
+ options.add_options()("help,h", "show help");
+ options.add_options()("verbose,v", "verbose output");
+ options.add_options()("force,f", "keep running after errors");
+#ifndef NO_GUI
+ options.add_options()("gui", "start gui");
+#endif
+
+ po::positional_options_description pos;
+#ifndef NO_PYTHON
+ options.add_options()("run", po::value<std::vector<std::string>>(), "python file to execute");
+ pos.add("run", -1);
+#endif
+ options.add_options()("version,V", "show version");
+
+ po::variables_map vm;
+ try {
+ po::parsed_options parsed = po::command_line_parser(argc, argv).options(options).positional(pos).run();
+
+ po::store(parsed, vm);
+
+ po::notify(vm);
+ }
+
+ catch (std::exception &e) {
+ std::cout << e.what() << "\n";
+ return 1;
+ }
+
+ if (vm.count("help") || argc == 1) {
+ std::cout << boost::filesystem::basename(argv[0])
+ << " -- Next Generation Place and Route (git "
+ "sha1 " GIT_COMMIT_HASH_STR ")\n";
+ std::cout << "\n";
+ std::cout << options << "\n";
+ return argc != 1;
+ }
+
+ if (vm.count("version")) {
+ std::cout << boost::filesystem::basename(argv[0])
+ << " -- Next Generation Place and Route (git "
+ "sha1 " GIT_COMMIT_HASH_STR ")\n";
+ return 1;
+ }
+
+ Context ctx(ArchArgs{});
+
+ if (vm.count("verbose")) {
+ ctx.verbose = true;
+ }
+
+ if (vm.count("force")) {
+ ctx.force = true;
+ }
+
+ if (vm.count("seed")) {
+ ctx.rngseed(vm["seed"].as<int>());
+ }
+
+#ifndef NO_PYTHON
+ if (vm.count("run")) {
+ init_python(argv[0], true);
+ python_export_global("ctx", ctx);
+
+ std::vector<std::string> files = vm["run"].as<std::vector<std::string>>();
+ for (auto filename : files)
+ execute_python_file(filename.c_str());
+
+ deinit_python();
+ }
+#endif
+
+#ifndef NO_GUI
+ if (vm.count("gui")) {
+ Application a(argc, argv);
+ MainWindow w;
+ w.show();
+
+ rc = a.exec();
+ }
+#endif
+ return rc;
+ } catch (log_execution_error_exception) {
+#if defined(_MSC_VER)
+ _exit(EXIT_FAILURE);
+#else
+ _Exit(EXIT_FAILURE);
+#endif
+ }
+}
+
+#endif