ecp5: Implementing (at least stubs) most of arch.cc
Signed-off-by: David Shah <davey1576@gmail.com>
This commit is contained in:
parent
074df03c59
commit
83303bae5a
285
ecp5/arch.cc
285
ecp5/arch.cc
@ -2,6 +2,7 @@
|
|||||||
* nextpnr -- Next Generation Place and Route
|
* nextpnr -- Next Generation Place and Route
|
||||||
*
|
*
|
||||||
* Copyright (C) 2018 Clifford Wolf <clifford@symbioticeda.com>
|
* 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
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
@ -19,80 +20,41 @@
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include <cstring>
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "nextpnr.h"
|
#include "nextpnr.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_BEGIN
|
NEXTPNR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
static std::tuple<int, int, std::string> split_identifier_name(const std::string &name)
|
||||||
|
{
|
||||||
|
size_t first_slash = name.find('/');
|
||||||
|
NPNR_ASSERT(first_slash != std::string::npos);
|
||||||
|
size_t second_slash = name.find('/', first_slash + 1);
|
||||||
|
NPNR_ASSERT(second_slash != std::string::npos);
|
||||||
|
return std::make_tuple(std::stoi(name.substr(1, first_slash)),
|
||||||
|
std::stoi(name.substr(first_slash + 2, second_slash - first_slash)),
|
||||||
|
name.substr(second_slash + 1));
|
||||||
|
};
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
// -----------------------------------------------------------------------
|
||||||
|
|
||||||
IdString Arch::belTypeToId(BelType type) const
|
IdString Arch::belTypeToId(BelType type) const
|
||||||
{
|
{
|
||||||
if (type == TYPE_ICESTORM_LC)
|
if (type == TYPE_TRELLIS_SLICE)
|
||||||
return id("ICESTORM_LC");
|
return id("TRELLIS_SLICE");
|
||||||
if (type == TYPE_ICESTORM_RAM)
|
if (type == TYPE_TRELLIS_IO)
|
||||||
return id("ICESTORM_RAM");
|
return id("TRELLIS_IO");
|
||||||
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();
|
return IdString();
|
||||||
}
|
}
|
||||||
|
|
||||||
BelType Arch::belTypeFromId(IdString type) const
|
BelType Arch::belTypeFromId(IdString type) const
|
||||||
{
|
{
|
||||||
if (type == id("ICESTORM_LC"))
|
if (type == id("TRELLIS_SLICE"))
|
||||||
return TYPE_ICESTORM_LC;
|
return TYPE_TRELLIS_SLICE;
|
||||||
if (type == id("ICESTORM_RAM"))
|
if (type == id("TRELLIS_IO"))
|
||||||
return TYPE_ICESTORM_RAM;
|
return TYPE_TRELLIS_IO;
|
||||||
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;
|
return TYPE_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,7 +63,9 @@ BelType Arch::belTypeFromId(IdString type) const
|
|||||||
void IdString::initialize_arch(const BaseCtx *ctx)
|
void IdString::initialize_arch(const BaseCtx *ctx)
|
||||||
{
|
{
|
||||||
#define X(t) initialize_add(ctx, #t, PIN_##t);
|
#define X(t) initialize_add(ctx, #t, PIN_##t);
|
||||||
|
|
||||||
#include "portpins.inc"
|
#include "portpins.inc"
|
||||||
|
|
||||||
#undef X
|
#undef X
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,102 +98,43 @@ Arch::Arch(ArchArgs args) : args(args)
|
|||||||
load_chipdb();
|
load_chipdb();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef ICE40_HX1K_ONLY
|
if (args.type == ArchArgs::LFE5U_25F) {
|
||||||
if (args.type == ArchArgs::HX1K) {
|
chip_info = get_chip_info(reinterpret_cast<const RelPtr<ChipInfoPOD> *>(chipdb_blob_25k));
|
||||||
chip_info = get_chip_info(reinterpret_cast<const RelPtr<ChipInfoPOD> *>(chipdb_blob_1k));
|
} else if (args.type == ArchArgs::LFE5U_45F) {
|
||||||
|
chip_info = get_chip_info(reinterpret_cast<const RelPtr<ChipInfoPOD> *>(chipdb_blob_45k));
|
||||||
|
} else if (args.type == ArchArgs::LFE5U_85F) {
|
||||||
|
chip_info = get_chip_info(reinterpret_cast<const RelPtr<ChipInfoPOD> *>(chipdb_blob_85k));
|
||||||
} else {
|
} else {
|
||||||
log_error("Unsupported iCE40 chip type.\n");
|
log_error("Unsupported ECP5 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()
|
std::string Arch::getChipName()
|
||||||
{
|
{
|
||||||
#ifdef ICE40_HX1K_ONLY
|
|
||||||
if (args.type == ArchArgs::HX1K) {
|
if (args.type == ArchArgs::LFE5U_25F) {
|
||||||
return "Lattice LP1K";
|
return "Lattice LFE5U-25F";
|
||||||
} else {
|
} else if (args.type == ArchArgs::LFE5U_45F) {
|
||||||
log_error("Unsupported iCE40 chip type.\n");
|
return "Lattice LFE5U-45F";
|
||||||
}
|
} else if (args.type == ArchArgs::LFE5U_85F) {
|
||||||
#else
|
return "Lattice LFE5U-85F";
|
||||||
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 {
|
} else {
|
||||||
log_error("Unknown chip\n");
|
log_error("Unknown chip\n");
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------
|
// -----------------------------------------------------------------------
|
||||||
|
|
||||||
IdString Arch::archArgsToId(ArchArgs args) const
|
IdString Arch::archArgsToId(ArchArgs args) const
|
||||||
{
|
{
|
||||||
if (args.type == ArchArgs::LP384)
|
if (args.type == ArchArgs::LFE5U_25F)
|
||||||
return id("lp384");
|
return id("lfe5u_25f");
|
||||||
if (args.type == ArchArgs::LP1K)
|
if (args.type == ArchArgs::LFE5U_45F)
|
||||||
return id("lp1k");
|
return id("lfe5u_45f");
|
||||||
if (args.type == ArchArgs::HX1K)
|
if (args.type == ArchArgs::LFE5U_85F)
|
||||||
return id("hx1k");
|
return id("lfe5u_85f");
|
||||||
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();
|
return IdString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -238,16 +143,23 @@ IdString Arch::archArgsToId(ArchArgs args) const
|
|||||||
BelId Arch::getBelByName(IdString name) const
|
BelId Arch::getBelByName(IdString name) const
|
||||||
{
|
{
|
||||||
BelId ret;
|
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);
|
auto it = bel_by_name.find(name);
|
||||||
if (it != bel_by_name.end())
|
if (it != bel_by_name.end())
|
||||||
ret.index = it->second;
|
return it->second;
|
||||||
|
|
||||||
|
Location loc;
|
||||||
|
std::string basename;
|
||||||
|
std::tie(loc.x, loc.y, basename) = split_identifier_name(name.str(this));
|
||||||
|
ret.location = loc;
|
||||||
|
const LocationTypePOD *loci = locInfo(ret);
|
||||||
|
for (int i = 0; i < loci->num_bels; i++) {
|
||||||
|
if (std::strcmp(loci->bel_data[i].name.get(), basename.c_str()) == 0) {
|
||||||
|
ret.index = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ret.index >= 0)
|
||||||
|
bel_by_name[name] = ret;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -255,17 +167,10 @@ BelRange Arch::getBelsAtSameTile(BelId bel) const
|
|||||||
{
|
{
|
||||||
BelRange br;
|
BelRange br;
|
||||||
NPNR_ASSERT(bel != BelId());
|
NPNR_ASSERT(bel != BelId());
|
||||||
// This requires Bels at the same tile are consecutive
|
br.b.cursor_tile = bel.location.y * chip_info->width + bel.location.x;
|
||||||
int x = chip_info->bel_data[bel.index].x;
|
br.e.cursor_tile = bel.location.y * chip_info->width + bel.location.x;
|
||||||
int y = chip_info->bel_data[bel.index].y;
|
br.b.cursor_index = 0;
|
||||||
int start = bel.index, end = bel.index;
|
br.e.cursor_index = locInfo(bel)->num_bels;
|
||||||
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;
|
return br;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -275,11 +180,11 @@ WireId Arch::getWireBelPin(BelId bel, PortPin pin) const
|
|||||||
|
|
||||||
NPNR_ASSERT(bel != BelId());
|
NPNR_ASSERT(bel != BelId());
|
||||||
|
|
||||||
int num_bel_wires = chip_info->bel_data[bel.index].num_bel_wires;
|
int num_bel_wires = locInfo(bel)->bel_data[bel.index].num_bel_wires;
|
||||||
const BelWirePOD *bel_wires = chip_info->bel_data[bel.index].bel_wires.get();
|
const BelWirePOD *bel_wires = locInfo(bel)->bel_data[bel.index].bel_wires.get();
|
||||||
|
|
||||||
for (int i = 0; i < num_bel_wires; i++)
|
for (int i = 0; i < num_bel_wires; i++)
|
||||||
if (bel_wires[i].port == pin) {
|
if (bel_wires[i].port == pin) {
|
||||||
|
ret.location = bel.location + bel_wires[i].rel_wire_loc;
|
||||||
ret.index = bel_wires[i].wire_index;
|
ret.index = bel_wires[i].wire_index;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -292,16 +197,23 @@ WireId Arch::getWireBelPin(BelId bel, PortPin pin) const
|
|||||||
WireId Arch::getWireByName(IdString name) const
|
WireId Arch::getWireByName(IdString name) const
|
||||||
{
|
{
|
||||||
WireId ret;
|
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);
|
auto it = wire_by_name.find(name);
|
||||||
if (it != wire_by_name.end())
|
if (it != wire_by_name.end())
|
||||||
ret.index = it->second;
|
return it->second;
|
||||||
|
|
||||||
|
Location loc;
|
||||||
|
std::string basename;
|
||||||
|
std::tie(loc.x, loc.y, basename) = split_identifier_name(name.str(this));
|
||||||
|
ret.location = loc;
|
||||||
|
const LocationTypePOD *loci = locInfo(ret);
|
||||||
|
for (int i = 0; i < loci->num_wires; i++) {
|
||||||
|
if (std::strcmp(loci->wire_data[i].name.get(), basename.c_str()) == 0) {
|
||||||
|
ret.index = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ret.index >= 0)
|
||||||
|
wire_by_name[name] = ret;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -309,34 +221,35 @@ WireId Arch::getWireByName(IdString name) const
|
|||||||
|
|
||||||
PipId Arch::getPipByName(IdString name) const
|
PipId Arch::getPipByName(IdString name) const
|
||||||
{
|
{
|
||||||
PipId ret;
|
|
||||||
|
|
||||||
if (pip_by_name.empty()) {
|
|
||||||
for (int i = 0; i < chip_info->num_pips; i++) {
|
|
||||||
PipId pip;
|
|
||||||
pip.index = i;
|
|
||||||
pip_by_name[getPipName(pip)] = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto it = pip_by_name.find(name);
|
auto it = pip_by_name.find(name);
|
||||||
if (it != pip_by_name.end())
|
if (it != pip_by_name.end())
|
||||||
ret.index = it->second;
|
return it->second;
|
||||||
|
|
||||||
return ret;
|
PipId ret;
|
||||||
|
Location loc;
|
||||||
|
std::string basename;
|
||||||
|
std::tie(loc.x, loc.y, basename) = split_identifier_name(name.str(this));
|
||||||
|
const LocationTypePOD *loci = locInfo(ret);
|
||||||
|
for (int i = 0; i < loci->num_pips; i++) {
|
||||||
|
PipId curr;
|
||||||
|
curr.location = loc;
|
||||||
|
curr.index = i;
|
||||||
|
pip_by_name[getPipName(curr)] = curr;
|
||||||
|
}
|
||||||
|
return pip_by_name[name];
|
||||||
}
|
}
|
||||||
|
|
||||||
IdString Arch::getPipName(PipId pip) const
|
IdString Arch::getPipName(PipId pip) const
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(pip != PipId());
|
NPNR_ASSERT(pip != PipId());
|
||||||
|
|
||||||
int x = chip_info->pip_data[pip.index].x;
|
int x = pip.location.x;
|
||||||
int y = chip_info->pip_data[pip.index].y;
|
int y = pip.location.y;
|
||||||
|
|
||||||
std::string src_name = chip_info->wire_data[chip_info->pip_data[pip.index].src].name.get();
|
std::string src_name = getWireName(getPipSrcWire(pip)).str(this);
|
||||||
std::replace(src_name.begin(), src_name.end(), '/', '.');
|
std::replace(src_name.begin(), src_name.end(), '/', '.');
|
||||||
|
|
||||||
std::string dst_name = chip_info->wire_data[chip_info->pip_data[pip.index].dst].name.get();
|
std::string dst_name = getWireName(getPipDstWire(pip)).str(this);
|
||||||
std::replace(dst_name.begin(), dst_name.end(), '/', '.');
|
std::replace(dst_name.begin(), dst_name.end(), '/', '.');
|
||||||
|
|
||||||
return id("X" + std::to_string(x) + "/Y" + std::to_string(y) + "/" + src_name + ".->." + dst_name);
|
return id("X" + std::to_string(x) + "/Y" + std::to_string(y) + "/" + src_name + ".->." + dst_name);
|
||||||
@ -383,4 +296,10 @@ std::vector<GraphicElement> Arch::getPipGraphics(PipId pip) const
|
|||||||
return ret;
|
return ret;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// -----------------------------------------------------------------------
|
||||||
|
|
||||||
|
bool Arch::isValidBelForCell(CellInfo *cell, BelId bel) const { return true; }
|
||||||
|
|
||||||
|
bool Arch::isBelLocationValid(BelId bel) const { return true; }
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_END
|
NEXTPNR_NAMESPACE_END
|
||||||
|
24
ecp5/arch.h
24
ecp5/arch.h
@ -2,6 +2,7 @@
|
|||||||
* nextpnr -- Next Generation Place and Route
|
* nextpnr -- Next Generation Place and Route
|
||||||
*
|
*
|
||||||
* Copyright (C) 2018 Clifford Wolf <clifford@symbioticeda.com>
|
* 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
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
* purpose with or without fee is hereby granted, provided that the above
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
@ -21,6 +22,8 @@
|
|||||||
#error Include "arch.h" via "nextpnr.h" only.
|
#error Include "arch.h" via "nextpnr.h" only.
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_BEGIN
|
NEXTPNR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
/**** Everything in this section must be kept in sync with chipdb.py ****/
|
/**** Everything in this section must be kept in sync with chipdb.py ****/
|
||||||
@ -340,9 +343,9 @@ struct Arch : BaseCtx
|
|||||||
{
|
{
|
||||||
const ChipInfoPOD *chip_info;
|
const ChipInfoPOD *chip_info;
|
||||||
|
|
||||||
mutable std::unordered_map<IdString, int> bel_by_name;
|
mutable std::unordered_map<IdString, BelId> bel_by_name;
|
||||||
mutable std::unordered_map<IdString, int> wire_by_name;
|
mutable std::unordered_map<IdString, WireId> wire_by_name;
|
||||||
mutable std::unordered_map<IdString, int> pip_by_name;
|
mutable std::unordered_map<IdString, PipId> pip_by_name;
|
||||||
|
|
||||||
std::unordered_map<BelId, IdString> bel_to_cell;
|
std::unordered_map<BelId, IdString> bel_to_cell;
|
||||||
std::unordered_map<WireId, IdString> wire_to_net;
|
std::unordered_map<WireId, IdString> wire_to_net;
|
||||||
@ -375,7 +378,9 @@ struct Arch : BaseCtx
|
|||||||
IdString getBelName(BelId bel) const
|
IdString getBelName(BelId bel) const
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(bel != BelId());
|
NPNR_ASSERT(bel != BelId());
|
||||||
return id(locInfo(bel)->bel_data[bel.index].name.get());
|
std::stringstream name;
|
||||||
|
name << "X" << bel.location.x << "/Y" << bel.location.y << "/" << locInfo(bel)->bel_data[bel.index].name.get();
|
||||||
|
return id(name.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t getBelChecksum(BelId bel) const { return bel.index; }
|
uint32_t getBelChecksum(BelId bel) const { return bel.index; }
|
||||||
@ -491,7 +496,11 @@ struct Arch : BaseCtx
|
|||||||
IdString getWireName(WireId wire) const
|
IdString getWireName(WireId wire) const
|
||||||
{
|
{
|
||||||
NPNR_ASSERT(wire != WireId());
|
NPNR_ASSERT(wire != WireId());
|
||||||
return id(locInfo(wire)->wire_data[wire.index].name.get());
|
|
||||||
|
std::stringstream name;
|
||||||
|
name << "X" << wire.location.x << "/Y" << wire.location.y << "/"
|
||||||
|
<< locInfo(wire)->wire_data[wire.index].name.get();
|
||||||
|
return id(name.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t getWireChecksum(WireId wire) const { return wire.index; }
|
uint32_t getWireChecksum(WireId wire) const { return wire.index; }
|
||||||
@ -724,6 +733,11 @@ struct Arch : BaseCtx
|
|||||||
bool isClockPort(const CellInfo *cell, IdString port) const;
|
bool isClockPort(const CellInfo *cell, IdString port) const;
|
||||||
// Return true if a port is a net
|
// Return true if a port is a net
|
||||||
bool isGlobalNet(const NetInfo *net) const;
|
bool isGlobalNet(const NetInfo *net) const;
|
||||||
|
|
||||||
|
// -------------------------------------------------
|
||||||
|
// Placement validity checks
|
||||||
|
bool isValidBelForCell(CellInfo *cell, BelId bel) const;
|
||||||
|
bool isBelLocationValid(BelId bel) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_END
|
NEXTPNR_NAMESPACE_END
|
||||||
|
@ -26,6 +26,50 @@
|
|||||||
|
|
||||||
NEXTPNR_NAMESPACE_BEGIN
|
NEXTPNR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
namespace PythonConversion {
|
||||||
|
|
||||||
|
template <> struct string_converter<BelId>
|
||||||
|
{
|
||||||
|
BelId from_str(Context *ctx, std::string name) { return ctx->getBelByName(ctx->id(name)); }
|
||||||
|
|
||||||
|
std::string to_str(Context *ctx, BelId id)
|
||||||
|
{
|
||||||
|
if (id == BelId())
|
||||||
|
throw bad_wrap();
|
||||||
|
return ctx->getBelName(id).str(ctx);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <> struct string_converter<BelType>
|
||||||
|
{
|
||||||
|
BelType from_str(Context *ctx, std::string name) { return ctx->belTypeFromId(ctx->id(name)); }
|
||||||
|
|
||||||
|
std::string to_str(Context *ctx, BelType typ) { return ctx->belTypeToId(typ).str(ctx); }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <> struct string_converter<WireId>
|
||||||
|
{
|
||||||
|
WireId from_str(Context *ctx, std::string name) { return ctx->getWireByName(ctx->id(name)); }
|
||||||
|
|
||||||
|
std::string to_str(Context *ctx, WireId id) { return ctx->getWireName(id).str(ctx); }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <> struct string_converter<PipId>
|
||||||
|
{
|
||||||
|
PipId from_str(Context *ctx, std::string name) { return ctx->getPipByName(ctx->id(name)); }
|
||||||
|
|
||||||
|
std::string to_str(Context *ctx, PipId id) { return ctx->getPipName(id).str(ctx); }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <> struct string_converter<PortPin>
|
||||||
|
{
|
||||||
|
PortPin from_str(Context *ctx, std::string name) { return ctx->portPinFromId(ctx->id(name)); }
|
||||||
|
|
||||||
|
std::string to_str(Context *ctx, PortPin id) { return ctx->portPinToId(id).str(ctx); }
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace PythonConversion
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_END
|
NEXTPNR_NAMESPACE_END
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
@ -74,7 +74,7 @@ struct Location
|
|||||||
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); }
|
inline Location operator+(const Location &a, const Location &b) { return Location(a.x + b.x, a.y + b.y); }
|
||||||
|
|
||||||
struct BelId
|
struct BelId
|
||||||
{
|
{
|
||||||
|
26
ecp5/place_legaliser.cc
Normal file
26
ecp5/place_legaliser.cc
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* nextpnr -- Next Generation Place and Route
|
||||||
|
*
|
||||||
|
* Copyright (C) 2018 David Shah <david@symbioticeda.com>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "place_legaliser.h"
|
||||||
|
|
||||||
|
NEXTPNR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
bool legalise_design(Context *ctx) { return true; }
|
||||||
|
|
||||||
|
NEXTPNR_NAMESPACE_END
|
31
ecp5/place_legaliser.h
Normal file
31
ecp5/place_legaliser.h
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* nextpnr -- Next Generation Place and Route
|
||||||
|
*
|
||||||
|
* Copyright (C) 2018 David Shah <david@symbioticeda.com>
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and/or distribute this software for any
|
||||||
|
* purpose with or without fee is hereby granted, provided that the above
|
||||||
|
* copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||||
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||||
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||||
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||||
|
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PLACE_LEGALISER_H
|
||||||
|
#define PLACE_LEGALISER_H
|
||||||
|
|
||||||
|
#include "nextpnr.h"
|
||||||
|
|
||||||
|
NEXTPNR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
bool legalise_design(Context *ctx);
|
||||||
|
|
||||||
|
NEXTPNR_NAMESPACE_END
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue
Block a user