ecp5: Implementing core arch.h functions

Signed-off-by: David Shah <davey1576@gmail.com>
This commit is contained in:
David Shah 2018-07-06 12:15:07 +02:00
parent c4af52dd5b
commit 7862d1b84b
6 changed files with 746 additions and 87 deletions

386
ecp5/arch.cc Normal file
View File

@ -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

View File

@ -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;
}

32
ecp5/arch_pybindings.cc Normal file
View File

@ -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

31
ecp5/arch_pybindings.h Normal file
View File

@ -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

View File

@ -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>

139
ecp5/main.cc Normal file
View File

@ -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