ecp5: Implementing core arch.h functions
Signed-off-by: David Shah <davey1576@gmail.com>
This commit is contained in:
parent
c4af52dd5b
commit
7862d1b84b
386
ecp5/arch.cc
Normal file
386
ecp5/arch.cc
Normal 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
|
195
ecp5/arch.h
195
ecp5/arch.h
@ -44,7 +44,7 @@ template <typename T> struct RelPtr
|
|||||||
};
|
};
|
||||||
|
|
||||||
NPNR_PACKED_STRUCT(struct BelWirePOD {
|
NPNR_PACKED_STRUCT(struct BelWirePOD {
|
||||||
Location rel_wire_loc;
|
LocationPOD rel_wire_loc;
|
||||||
int32_t wire_index;
|
int32_t wire_index;
|
||||||
PortPin port;
|
PortPin port;
|
||||||
});
|
});
|
||||||
@ -59,23 +59,23 @@ NPNR_PACKED_STRUCT(struct BelInfoPOD {
|
|||||||
});
|
});
|
||||||
|
|
||||||
NPNR_PACKED_STRUCT(struct BelPortPOD {
|
NPNR_PACKED_STRUCT(struct BelPortPOD {
|
||||||
Location rel_bel_loc;
|
LocationPOD rel_bel_loc;
|
||||||
int32_t bel_index;
|
int32_t bel_index;
|
||||||
PortPin port;
|
PortPin port;
|
||||||
});
|
});
|
||||||
|
|
||||||
NPNR_PACKED_STRUCT(struct PipInfoPOD {
|
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 src_idx, dst_idx;
|
||||||
int32_t delay;
|
int32_t delay;
|
||||||
Location rel_tile_loc;
|
LocationPOD rel_tile_loc;
|
||||||
int16_t tile_type;
|
int16_t tile_type;
|
||||||
int8_t pip_type;
|
int8_t pip_type;
|
||||||
int8_t padding_0;
|
int8_t padding_0;
|
||||||
});
|
});
|
||||||
|
|
||||||
NPNR_PACKED_STRUCT(struct PipLocatorPOD {
|
NPNR_PACKED_STRUCT(struct PipLocatorPOD {
|
||||||
Location rel_loc;
|
LocationPOD rel_loc;
|
||||||
int32_t index;
|
int32_t index;
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -98,21 +98,20 @@ NPNR_PACKED_STRUCT(struct LocationTypePOD {
|
|||||||
|
|
||||||
NPNR_PACKED_STRUCT(struct ChipInfoPOD {
|
NPNR_PACKED_STRUCT(struct ChipInfoPOD {
|
||||||
int32_t width, height;
|
int32_t width, height;
|
||||||
|
int32_t num_tiles;
|
||||||
int32_t num_location_types;
|
int32_t num_location_types;
|
||||||
RelPtr<LocationTypePOD> locations;
|
RelPtr<LocationTypePOD> locations;
|
||||||
RelPtr<int32_t> location_type;
|
RelPtr<int32_t> location_type;
|
||||||
});
|
});
|
||||||
|
|
||||||
#if defined(_MSC_VER)
|
#if defined(_MSC_VER)
|
||||||
extern const char *chipdb_blob_384;
|
extern const char *chipdb_blob_25k;
|
||||||
extern const char *chipdb_blob_1k;
|
extern const char *chipdb_blob_45k;
|
||||||
extern const char *chipdb_blob_5k;
|
extern const char *chipdb_blob_85k;
|
||||||
extern const char *chipdb_blob_8k;
|
|
||||||
#else
|
#else
|
||||||
extern const char chipdb_blob_384[];
|
extern const char chipdb_blob_25k[];
|
||||||
extern const char chipdb_blob_1k[];
|
extern const char chipdb_blob_45k[];
|
||||||
extern const char chipdb_blob_5k[];
|
extern const char chipdb_blob_85k[];
|
||||||
extern const char chipdb_blob_8k[];
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/************************ End of chipdb section. ************************/
|
/************************ End of chipdb section. ************************/
|
||||||
@ -126,7 +125,8 @@ struct BelIterator
|
|||||||
BelIterator operator++()
|
BelIterator operator++()
|
||||||
{
|
{
|
||||||
cursor_index++;
|
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_index = 0;
|
||||||
cursor_tile++;
|
cursor_tile++;
|
||||||
}
|
}
|
||||||
@ -135,7 +135,7 @@ struct BelIterator
|
|||||||
BelIterator operator++(int)
|
BelIterator operator++(int)
|
||||||
{
|
{
|
||||||
BelIterator prior(*this);
|
BelIterator prior(*this);
|
||||||
cursor++;
|
++(*this);
|
||||||
return prior;
|
return prior;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,7 +171,7 @@ struct BelRange
|
|||||||
struct BelPinIterator
|
struct BelPinIterator
|
||||||
{
|
{
|
||||||
const BelPortPOD *ptr = nullptr;
|
const BelPortPOD *ptr = nullptr;
|
||||||
const Location wire_loc;
|
Location wire_loc;
|
||||||
void operator++() { ptr++; }
|
void operator++() { ptr++; }
|
||||||
bool operator!=(const BelPinIterator &other) const { return ptr != other.ptr; }
|
bool operator!=(const BelPinIterator &other) const { return ptr != other.ptr; }
|
||||||
|
|
||||||
@ -203,7 +203,8 @@ struct WireIterator
|
|||||||
WireIterator operator++()
|
WireIterator operator++()
|
||||||
{
|
{
|
||||||
cursor_index++;
|
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_index = 0;
|
||||||
cursor_tile++;
|
cursor_tile++;
|
||||||
}
|
}
|
||||||
@ -212,7 +213,7 @@ struct WireIterator
|
|||||||
WireIterator operator++(int)
|
WireIterator operator++(int)
|
||||||
{
|
{
|
||||||
WireIterator prior(*this);
|
WireIterator prior(*this);
|
||||||
cursor++;
|
++(*this);
|
||||||
return prior;
|
return prior;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -254,7 +255,8 @@ struct AllPipIterator
|
|||||||
AllPipIterator operator++()
|
AllPipIterator operator++()
|
||||||
{
|
{
|
||||||
cursor_index++;
|
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_index = 0;
|
||||||
cursor_tile++;
|
cursor_tile++;
|
||||||
}
|
}
|
||||||
@ -262,8 +264,8 @@ struct AllPipIterator
|
|||||||
}
|
}
|
||||||
AllPipIterator operator++(int)
|
AllPipIterator operator++(int)
|
||||||
{
|
{
|
||||||
WireIterator prior(*this);
|
AllPipIterator prior(*this);
|
||||||
cursor++;
|
++(*this);
|
||||||
return prior;
|
return prior;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -309,7 +311,7 @@ struct PipIterator
|
|||||||
{
|
{
|
||||||
PipId ret;
|
PipId ret;
|
||||||
ret.index = cursor->index;
|
ret.index = cursor->index;
|
||||||
ret.location = wire_loc + cursor->location;
|
ret.location = wire_loc + cursor->rel_loc;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -337,7 +339,6 @@ struct ArchArgs
|
|||||||
struct Arch : BaseCtx
|
struct Arch : BaseCtx
|
||||||
{
|
{
|
||||||
const ChipInfoPOD *chip_info;
|
const ChipInfoPOD *chip_info;
|
||||||
const PackageInfoPOD *package_info;
|
|
||||||
|
|
||||||
mutable std::unordered_map<IdString, int> bel_by_name;
|
mutable std::unordered_map<IdString, int> bel_by_name;
|
||||||
mutable std::unordered_map<IdString, int> wire_by_name;
|
mutable std::unordered_map<IdString, int> wire_by_name;
|
||||||
@ -366,10 +367,15 @@ struct Arch : BaseCtx
|
|||||||
|
|
||||||
BelId getBelByName(IdString name) const;
|
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
|
IdString getBelName(BelId bel) const
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(bel != BelId());
|
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; }
|
uint32_t getBelChecksum(BelId bel) const { return bel.index; }
|
||||||
@ -386,35 +392,46 @@ struct Arch : BaseCtx
|
|||||||
void unbindBel(BelId bel)
|
void unbindBel(BelId bel)
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(bel != BelId());
|
NPNR_ASSERT(bel != BelId());
|
||||||
NPNR_ASSERT(bel_to_cell[bel.index] != IdString());
|
NPNR_ASSERT(bel_to_cell[bel] != IdString());
|
||||||
cells[bel_to_cell[bel.index]]->bel = BelId();
|
cells[bel_to_cell[bel]]->bel = BelId();
|
||||||
cells[bel_to_cell[bel.index]]->belStrength = STRENGTH_NONE;
|
cells[bel_to_cell[bel]]->belStrength = STRENGTH_NONE;
|
||||||
bel_to_cell[bel.index] = IdString();
|
bel_to_cell[bel] = IdString();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool checkBelAvail(BelId bel) const
|
bool checkBelAvail(BelId bel) const
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(bel != BelId());
|
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
|
IdString getBoundBelCell(BelId bel) const
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(bel != BelId());
|
NPNR_ASSERT(bel != BelId());
|
||||||
|
if (bel_to_cell.find(bel) == bel_to_cell.end())
|
||||||
|
return IdString();
|
||||||
|
else
|
||||||
return bel_to_cell.at(bel);
|
return bel_to_cell.at(bel);
|
||||||
}
|
}
|
||||||
|
|
||||||
IdString getConflictingBelCell(BelId bel) const
|
IdString getConflictingBelCell(BelId bel) const
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(bel != BelId());
|
NPNR_ASSERT(bel != BelId());
|
||||||
|
if (bel_to_cell.find(bel) == bel_to_cell.end())
|
||||||
|
return IdString();
|
||||||
|
else
|
||||||
return bel_to_cell.at(bel);
|
return bel_to_cell.at(bel);
|
||||||
}
|
}
|
||||||
|
|
||||||
BelRange getBels() const
|
BelRange getBels() const
|
||||||
{
|
{
|
||||||
BelRange range;
|
BelRange range;
|
||||||
range.b.cursor = 0;
|
range.b.cursor_tile = 0;
|
||||||
range.e.cursor = chip_info->num_bels;
|
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;
|
return range;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -437,7 +454,7 @@ struct Arch : BaseCtx
|
|||||||
BelType getBelType(BelId bel) const
|
BelType getBelType(BelId bel) const
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(bel != BelId());
|
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;
|
WireId getWireBelPin(BelId bel, PortPin pin) const;
|
||||||
@ -447,9 +464,10 @@ struct Arch : BaseCtx
|
|||||||
BelPin ret;
|
BelPin ret;
|
||||||
NPNR_ASSERT(wire != WireId());
|
NPNR_ASSERT(wire != WireId());
|
||||||
|
|
||||||
if (chip_info->wire_data[wire.index].bel_uphill.bel_index >= 0) {
|
if (locInfo(wire)->wire_data[wire.index].bel_uphill.bel_index >= 0) {
|
||||||
ret.bel.index = chip_info->wire_data[wire.index].bel_uphill.bel_index;
|
ret.bel.index = locInfo(wire)->wire_data[wire.index].bel_uphill.bel_index;
|
||||||
ret.pin = chip_info->wire_data[wire.index].bel_uphill.port;
|
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;
|
return ret;
|
||||||
@ -459,8 +477,10 @@ struct Arch : BaseCtx
|
|||||||
{
|
{
|
||||||
BelPinRange range;
|
BelPinRange range;
|
||||||
NPNR_ASSERT(wire != WireId());
|
NPNR_ASSERT(wire != WireId());
|
||||||
range.b.ptr = chip_info->wire_data[wire.index].bels_downhill.get();
|
range.b.ptr = locInfo(wire)->wire_data[wire.index].bels_downhill.get();
|
||||||
range.e.ptr = range.b.ptr + chip_info->wire_data[wire.index].num_bels_downhill;
|
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;
|
return range;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -471,7 +491,7 @@ struct Arch : BaseCtx
|
|||||||
IdString getWireName(WireId wire) const
|
IdString getWireName(WireId wire) const
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(wire != WireId());
|
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; }
|
uint32_t getWireChecksum(WireId wire) const { return wire.index; }
|
||||||
@ -479,8 +499,8 @@ struct Arch : BaseCtx
|
|||||||
void bindWire(WireId wire, IdString net, PlaceStrength strength)
|
void bindWire(WireId wire, IdString net, PlaceStrength strength)
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(wire != WireId());
|
NPNR_ASSERT(wire != WireId());
|
||||||
NPNR_ASSERT(wire_to_net[wire.index] == IdString());
|
NPNR_ASSERT(wire_to_net[wire] == IdString());
|
||||||
wire_to_net[wire.index] = net;
|
wire_to_net[wire] = net;
|
||||||
nets[net]->wires[wire].pip = PipId();
|
nets[net]->wires[wire].pip = PipId();
|
||||||
nets[net]->wires[wire].strength = strength;
|
nets[net]->wires[wire].strength = strength;
|
||||||
}
|
}
|
||||||
@ -488,45 +508,55 @@ struct Arch : BaseCtx
|
|||||||
void unbindWire(WireId wire)
|
void unbindWire(WireId wire)
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(wire != WireId());
|
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);
|
auto it = net_wires.find(wire);
|
||||||
NPNR_ASSERT(it != net_wires.end());
|
NPNR_ASSERT(it != net_wires.end());
|
||||||
|
|
||||||
auto pip = it->second.pip;
|
auto pip = it->second.pip;
|
||||||
if (pip != PipId()) {
|
if (pip != PipId()) {
|
||||||
pip_to_net[pip.index] = IdString();
|
pip_to_net[pip] = IdString();
|
||||||
switches_locked[chip_info->pip_data[pip.index].switch_index] = IdString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
net_wires.erase(it);
|
net_wires.erase(it);
|
||||||
wire_to_net[wire.index] = IdString();
|
wire_to_net[wire] = IdString();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool checkWireAvail(WireId wire) const
|
bool checkWireAvail(WireId wire) const
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(wire != WireId());
|
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
|
IdString getBoundWireNet(WireId wire) const
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(wire != WireId());
|
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
|
IdString getConflictingWireNet(WireId wire) const
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(wire != WireId());
|
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 getWires() const
|
||||||
{
|
{
|
||||||
WireRange range;
|
WireRange range;
|
||||||
range.b.cursor = 0;
|
range.b.cursor_tile = 0;
|
||||||
range.e.cursor = chip_info->num_wires;
|
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;
|
return range;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -540,16 +570,15 @@ struct Arch : BaseCtx
|
|||||||
void bindPip(PipId pip, IdString net, PlaceStrength strength)
|
void bindPip(PipId pip, IdString net, PlaceStrength strength)
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(pip != PipId());
|
NPNR_ASSERT(pip != PipId());
|
||||||
NPNR_ASSERT(pip_to_net[pip.index] == IdString());
|
NPNR_ASSERT(pip_to_net[pip] == IdString());
|
||||||
NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] == IdString());
|
|
||||||
|
|
||||||
pip_to_net[pip.index] = net;
|
pip_to_net[pip] = net;
|
||||||
switches_locked[chip_info->pip_data[pip.index].switch_index] = net;
|
|
||||||
|
|
||||||
WireId dst;
|
WireId dst;
|
||||||
dst.index = chip_info->pip_data[pip.index].dst;
|
dst.index = locInfo(pip)->pip_data[pip.index].dst_idx;
|
||||||
NPNR_ASSERT(wire_to_net[dst.index] == IdString());
|
dst.location = pip.location + locInfo(pip)->pip_data[pip.index].rel_dst_loc;
|
||||||
wire_to_net[dst.index] = net;
|
NPNR_ASSERT(wire_to_net[dst] == IdString());
|
||||||
|
wire_to_net[dst] = net;
|
||||||
nets[net]->wires[dst].pip = pip;
|
nets[net]->wires[dst].pip = pip;
|
||||||
nets[net]->wires[dst].strength = strength;
|
nets[net]->wires[dst].strength = strength;
|
||||||
}
|
}
|
||||||
@ -557,42 +586,52 @@ struct Arch : BaseCtx
|
|||||||
void unbindPip(PipId pip)
|
void unbindPip(PipId pip)
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(pip != PipId());
|
NPNR_ASSERT(pip != PipId());
|
||||||
NPNR_ASSERT(pip_to_net[pip.index] != IdString());
|
NPNR_ASSERT(pip_to_net[pip] != IdString());
|
||||||
NPNR_ASSERT(switches_locked[chip_info->pip_data[pip.index].switch_index] != IdString());
|
|
||||||
|
|
||||||
WireId dst;
|
WireId dst;
|
||||||
dst.index = chip_info->pip_data[pip.index].dst;
|
dst.index = locInfo(pip)->pip_data[pip.index].dst_idx;
|
||||||
NPNR_ASSERT(wire_to_net[dst.index] != IdString());
|
dst.location = pip.location + locInfo(pip)->pip_data[pip.index].rel_dst_loc;
|
||||||
wire_to_net[dst.index] = IdString();
|
NPNR_ASSERT(wire_to_net[dst] != IdString());
|
||||||
nets[pip_to_net[pip.index]]->wires.erase(dst);
|
wire_to_net[dst] = IdString();
|
||||||
|
nets[pip_to_net[pip]]->wires.erase(dst);
|
||||||
|
|
||||||
pip_to_net[pip.index] = IdString();
|
pip_to_net[pip] = IdString();
|
||||||
switches_locked[chip_info->pip_data[pip.index].switch_index] = IdString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool checkPipAvail(PipId pip) const
|
bool checkPipAvail(PipId pip) const
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(pip != PipId());
|
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
|
IdString getBoundPipNet(PipId pip) const
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(pip != PipId());
|
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
|
IdString getConflictingPipNet(PipId pip) const
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(pip != PipId());
|
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 getPips() const
|
||||||
{
|
{
|
||||||
AllPipRange range;
|
AllPipRange range;
|
||||||
range.b.cursor = 0;
|
range.b.cursor_tile = 0;
|
||||||
range.e.cursor = chip_info->num_pips;
|
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;
|
return range;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -600,7 +639,8 @@ struct Arch : BaseCtx
|
|||||||
{
|
{
|
||||||
WireId wire;
|
WireId wire;
|
||||||
NPNR_ASSERT(pip != PipId());
|
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;
|
return wire;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -608,7 +648,8 @@ struct Arch : BaseCtx
|
|||||||
{
|
{
|
||||||
WireId wire;
|
WireId wire;
|
||||||
NPNR_ASSERT(pip != PipId());
|
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;
|
return wire;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -616,7 +657,7 @@ struct Arch : BaseCtx
|
|||||||
{
|
{
|
||||||
DelayInfo delay;
|
DelayInfo delay;
|
||||||
NPNR_ASSERT(pip != PipId());
|
NPNR_ASSERT(pip != PipId());
|
||||||
delay.delay = chip_info->pip_data[pip.index].delay;
|
delay.delay = locInfo(pip)->pip_data[pip.index].delay;
|
||||||
return delay;
|
return delay;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -624,8 +665,8 @@ struct Arch : BaseCtx
|
|||||||
{
|
{
|
||||||
PipRange range;
|
PipRange range;
|
||||||
NPNR_ASSERT(wire != WireId());
|
NPNR_ASSERT(wire != WireId());
|
||||||
range.b.cursor = chip_info->wire_data[wire.index].pips_downhill.get();
|
range.b.cursor = locInfo(wire)->wire_data[wire.index].pips_downhill.get();
|
||||||
range.e.cursor = range.b.cursor + chip_info->wire_data[wire.index].num_downhill;
|
range.e.cursor = range.b.cursor + locInfo(wire)->wire_data[wire.index].num_downhill;
|
||||||
return range;
|
return range;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -633,8 +674,8 @@ struct Arch : BaseCtx
|
|||||||
{
|
{
|
||||||
PipRange range;
|
PipRange range;
|
||||||
NPNR_ASSERT(wire != WireId());
|
NPNR_ASSERT(wire != WireId());
|
||||||
range.b.cursor = chip_info->wire_data[wire.index].pips_uphill.get();
|
range.b.cursor = locInfo(wire)->wire_data[wire.index].pips_uphill.get();
|
||||||
range.e.cursor = range.b.cursor + chip_info->wire_data[wire.index].num_uphill;
|
range.e.cursor = range.b.cursor + locInfo(wire)->wire_data[wire.index].num_uphill;
|
||||||
return range;
|
return range;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
32
ecp5/arch_pybindings.cc
Normal file
32
ecp5/arch_pybindings.cc
Normal 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
31
ecp5/arch_pybindings.h
Normal 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
|
@ -60,13 +60,21 @@ enum PortPin : int32_t
|
|||||||
PIN_MAXIDX
|
PIN_MAXIDX
|
||||||
};
|
};
|
||||||
|
|
||||||
NPNR_PACKED_STRUCT(struct Location {
|
NPNR_PACKED_STRUCT(struct LocationPOD { int16_t x, y; });
|
||||||
|
|
||||||
|
struct Location
|
||||||
|
{
|
||||||
int16_t x = -1, y = -1;
|
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; }
|
||||||
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
|
struct BelId
|
||||||
{
|
{
|
||||||
@ -91,29 +99,51 @@ struct PipId
|
|||||||
Location location;
|
Location location;
|
||||||
int32_t index = -1;
|
int32_t index = -1;
|
||||||
|
|
||||||
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 WireId &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
|
NEXTPNR_NAMESPACE_END
|
||||||
|
|
||||||
namespace std {
|
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>
|
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>
|
template <> struct hash<NEXTPNR_NAMESPACE_PREFIX WireId>
|
||||||
{
|
{
|
||||||
std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX WireId &wire) const noexcept
|
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>
|
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>
|
template <> struct hash<NEXTPNR_NAMESPACE_PREFIX BelType> : hash<int>
|
||||||
|
139
ecp5/main.cc
Normal file
139
ecp5/main.cc
Normal 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
|
Loading…
Reference in New Issue
Block a user