wip
This commit is contained in:
parent
a0091eb44b
commit
048bae1d85
@ -44,7 +44,7 @@ if (EXTERNAL_CHIPDB)
|
||||
endif()
|
||||
|
||||
# List of families to build
|
||||
set(FAMILIES generic ice40 ecp5)
|
||||
set(FAMILIES generic ice40 ecp5 leuctra)
|
||||
|
||||
set(ARCH "" CACHE STRING "Architecture family for nextpnr build")
|
||||
set_property(CACHE ARCH PROPERTY STRINGS ${FAMILIES})
|
||||
@ -67,6 +67,11 @@ foreach(item ${ARCH})
|
||||
if (NOT item IN_LIST FAMILIES)
|
||||
message(FATAL_ERROR "Architecture '${item}' not in list of supported architectures")
|
||||
endif()
|
||||
if (item STREQUAL "leuctra")
|
||||
if (NOT EXTERNAL_CHIPDB)
|
||||
message(FATAL_ERROR "The leuctra backend requires setting -DEXTERNAL_CHIPDB=ON")
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
|
@ -313,7 +313,7 @@ void DesignWidget::newContext(Context *ctx)
|
||||
wireMap[std::pair<int, int>(wire->x, wire->y)].push_back(wireid);
|
||||
}
|
||||
#endif
|
||||
#ifdef ARCH_ECP5
|
||||
#if defined(ARCH_ECP5) || defined(ARCH_LEUCTRA)
|
||||
for (const auto &wire : ctx->getWires()) {
|
||||
wireMap[std::pair<int, int>(wire.location.x, wire.location.y)].push_back(wire);
|
||||
}
|
||||
|
0
gui/leuctra/family.cmake
Normal file
0
gui/leuctra/family.cmake
Normal file
51
gui/leuctra/mainwindow.cc
Normal file
51
gui/leuctra/mainwindow.cc
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* nextpnr -- Next Generation Place and Route
|
||||
*
|
||||
* Copyright (C) 2018 Miodrag Milanovic <miodrag@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 "mainwindow.h"
|
||||
|
||||
static void initMainResource() { Q_INIT_RESOURCE(nextpnr); }
|
||||
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
MainWindow::MainWindow(std::unique_ptr<Context> context, ArchArgs args, QWidget *parent)
|
||||
: BaseMainWindow(std::move(context), args, parent)
|
||||
{
|
||||
initMainResource();
|
||||
|
||||
std::string title = "nextpnr-leuctra - [EMPTY]";
|
||||
setWindowTitle(title.c_str());
|
||||
|
||||
connect(this, &BaseMainWindow::contextChanged, this, &MainWindow::newContext);
|
||||
|
||||
createMenu();
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow() {}
|
||||
|
||||
void MainWindow::newContext(Context *ctx)
|
||||
{
|
||||
std::string title = "nextpnr-leuctra - " + ctx->getChipName();
|
||||
setWindowTitle(title.c_str());
|
||||
}
|
||||
|
||||
void MainWindow::createMenu() {}
|
||||
|
||||
void MainWindow::new_proj() {}
|
||||
|
||||
NEXTPNR_NAMESPACE_END
|
45
gui/leuctra/mainwindow.h
Normal file
45
gui/leuctra/mainwindow.h
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* nextpnr -- Next Generation Place and Route
|
||||
*
|
||||
* Copyright (C) 2018 Miodrag Milanovic <miodrag@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 MAINWINDOW_H
|
||||
#define MAINWINDOW_H
|
||||
|
||||
#include "../basewindow.h"
|
||||
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
class MainWindow : public BaseMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit MainWindow(std::unique_ptr<Context> context, ArchArgs args, QWidget *parent = 0);
|
||||
virtual ~MainWindow();
|
||||
|
||||
public:
|
||||
void createMenu();
|
||||
|
||||
protected Q_SLOTS:
|
||||
void new_proj() override;
|
||||
void newContext(Context *ctx);
|
||||
};
|
||||
|
||||
NEXTPNR_NAMESPACE_END
|
||||
|
||||
#endif // MAINWINDOW_H
|
2
gui/leuctra/nextpnr.qrc
Normal file
2
gui/leuctra/nextpnr.qrc
Normal file
@ -0,0 +1,2 @@
|
||||
<RCC>
|
||||
</RCC>
|
556
leuctra/arch.cc
Normal file
556
leuctra/arch.cc
Normal file
@ -0,0 +1,556 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "nextpnr.h"
|
||||
#include "placer1.h"
|
||||
#include "router1.h"
|
||||
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
static std::tuple<int, int, std::string> split_identifier_name(const std::string &name)
|
||||
{
|
||||
size_t first_slash = name.find('/');
|
||||
NPNR_ASSERT(first_slash != std::string::npos);
|
||||
size_t second_slash = name.find('/', first_slash + 1);
|
||||
NPNR_ASSERT(second_slash != std::string::npos);
|
||||
return std::make_tuple(std::stoi(name.substr(1, first_slash)),
|
||||
std::stoi(name.substr(first_slash + 2, second_slash - first_slash)),
|
||||
name.substr(second_slash + 1));
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
void IdString::initialize_arch(const BaseCtx *ctx)
|
||||
{
|
||||
// Nothing here -- IdString is actually initialized in the constructor,
|
||||
// because we need to have bba loaded.
|
||||
}
|
||||
|
||||
// Given a device name, figure out what family it belongs to.
|
||||
static Arch::Family device_to_family(const std::string &device)
|
||||
{
|
||||
size_t pos = 0;
|
||||
|
||||
// Skip the prefix.
|
||||
if (device.substr(0, 2) == "xc")
|
||||
pos += 2;
|
||||
else if (device.substr(0, 2) == "xa")
|
||||
pos += 2;
|
||||
else if (device.substr(0, 2) == "xq")
|
||||
pos += 2;
|
||||
else if (device.substr(0, 3) == "xqr")
|
||||
pos += 3;
|
||||
auto raw = device.substr(pos);
|
||||
|
||||
if (raw.substr(0, 2) == "vu" || raw.substr(0, 2) == "ku") {
|
||||
// Ultrascale or Ultrascale+ (needs to be checked before original Virtex).
|
||||
if (raw.substr(raw.size() - 1) == "p")
|
||||
return Arch::FAMILY_ULTRASCALE_PLUS;
|
||||
return Arch::FAMILY_ULTRASCALE;
|
||||
} else if (raw.substr(0, 2) == "zu") {
|
||||
// Zynq Ultrascale+.
|
||||
return Arch::FAMILY_ULTRASCALE_PLUS;
|
||||
} else if (raw.substr(0, 1) == "7") {
|
||||
// 7 Series.
|
||||
return Arch::FAMILY_SERIES7;
|
||||
} else if (raw.substr(0, 2) == "6s") {
|
||||
return Arch::FAMILY_SPARTAN6;
|
||||
} else if (raw.substr(0, 2) == "6v") {
|
||||
return Arch::FAMILY_VIRTEX6;
|
||||
} else if (raw.substr(0, 2) == "5v") {
|
||||
return Arch::FAMILY_VIRTEX5;
|
||||
} else if (raw.substr(0, 2) == "4v") {
|
||||
return Arch::FAMILY_VIRTEX4;
|
||||
} else if (raw.substr(0, 3) == "3sd") {
|
||||
// Needs to be checked before other Spartan 3 variants.
|
||||
return Arch::FAMILY_SPARTAN3ADSP;
|
||||
} else if (raw.substr(0, 2) == "3s") {
|
||||
// One of many Spartan 3 variants.
|
||||
if (raw.substr(raw.size() - 1) == "e")
|
||||
return Arch::FAMILY_SPARTAN3E;
|
||||
if (raw.substr(raw.size() - 1) == "a")
|
||||
return Arch::FAMILY_SPARTAN3A;
|
||||
if (raw.substr(raw.size() - 2) == "an")
|
||||
return Arch::FAMILY_SPARTAN3A;
|
||||
return Arch::FAMILY_SPARTAN3;
|
||||
} else if (raw.substr(0, 3) == "2vp") {
|
||||
// Virtex 2 Pro.
|
||||
return Arch::FAMILY_VIRTEX2P;
|
||||
} else if (raw.substr(0, 2) == "2v") {
|
||||
// Virtex 2.
|
||||
return Arch::FAMILY_VIRTEX2;
|
||||
} else if (raw.substr(0, 1) == "v" || raw.substr(0, 2) == "2s") {
|
||||
// Virtex or Virtex E.
|
||||
if (raw.substr(raw.size() - 1) == "e")
|
||||
return Arch::FAMILY_VIRTEXE;
|
||||
return Arch::FAMILY_VIRTEX;
|
||||
} else if (raw.substr(0, 1) == "s") {
|
||||
// Spartan or Spartan XL.
|
||||
if (raw.size() >= 2 && raw.substr(raw.size() - 2) == "xl")
|
||||
return Arch::FAMILY_SPARTANXL;
|
||||
return Arch::FAMILY_XC4000E;
|
||||
} else if (raw.substr(0, 2) == "40") {
|
||||
// One of the xc4000 families.
|
||||
if (raw.substr(raw.size() - 1) == "e")
|
||||
return Arch::FAMILY_XC4000E;
|
||||
if (raw.substr(raw.size() - 2) == "ex")
|
||||
return Arch::FAMILY_XC4000EX;
|
||||
if (raw.substr(raw.size() - 2) == "xl")
|
||||
return Arch::FAMILY_XC4000EX;
|
||||
if (raw.size() >= 3 && raw.substr(raw.size() - 3) == "xla")
|
||||
return Arch::FAMILY_XC4000XLA;
|
||||
if (raw.substr(raw.size() - 2) == "xv")
|
||||
return Arch::FAMILY_XC4000XV;
|
||||
}
|
||||
log_error("Unknown device family.\n");
|
||||
}
|
||||
|
||||
static std::string family_name(Arch::Family family) {
|
||||
switch(family) {
|
||||
case Arch::FAMILY_XC4000E:
|
||||
return "xc4000e";
|
||||
case Arch::FAMILY_XC4000EX:
|
||||
return "xc4000ex";
|
||||
case Arch::FAMILY_XC4000XLA:
|
||||
return "xc4000xla";
|
||||
case Arch::FAMILY_XC4000XV:
|
||||
return "xc4000xv";
|
||||
case Arch::FAMILY_SPARTANXL:
|
||||
return "spartanxl";
|
||||
case Arch::FAMILY_VIRTEX:
|
||||
return "virtex";
|
||||
case Arch::FAMILY_VIRTEXE:
|
||||
return "virtexe";
|
||||
case Arch::FAMILY_VIRTEX2:
|
||||
return "virtex2";
|
||||
case Arch::FAMILY_VIRTEX2P:
|
||||
return "virtex2p";
|
||||
case Arch::FAMILY_SPARTAN3:
|
||||
return "spartan3";
|
||||
case Arch::FAMILY_SPARTAN3E:
|
||||
return "spartan3e";
|
||||
case Arch::FAMILY_SPARTAN3A:
|
||||
return "spartan3a";
|
||||
case Arch::FAMILY_SPARTAN3ADSP:
|
||||
return "spartan3adsp";
|
||||
case Arch::FAMILY_VIRTEX4:
|
||||
return "virtex4";
|
||||
case Arch::FAMILY_VIRTEX5:
|
||||
return "virtex5";
|
||||
case Arch::FAMILY_VIRTEX6:
|
||||
return "virtex6";
|
||||
case Arch::FAMILY_SPARTAN6:
|
||||
return "spartan6";
|
||||
case Arch::FAMILY_SERIES7:
|
||||
return "series7";
|
||||
case Arch::FAMILY_ULTRASCALE:
|
||||
return "ultrascale";
|
||||
case Arch::FAMILY_ULTRASCALE_PLUS:
|
||||
return "ultrascaleplus";
|
||||
}
|
||||
NPNR_ASSERT_FALSE("strange family");
|
||||
return "";
|
||||
}
|
||||
|
||||
Arch::Arch(ArchArgs args) : args(args)
|
||||
{
|
||||
// Select and load family bba.
|
||||
family = device_to_family(args.device);
|
||||
std::string fname = family_name(family);
|
||||
std::string family_filename = EXTERNAL_CHIPDB_ROOT "/leuctra/" + fname + ".bin";
|
||||
try {
|
||||
mmap.open(family_filename);
|
||||
if (!mmap.is_open())
|
||||
log_error("Unable to read chipdb %s\n", family_filename.c_str());
|
||||
} catch (...) {
|
||||
log_error("Unable to read chipdb %s\n", family_filename.c_str());
|
||||
}
|
||||
family_info = reinterpret_cast<const FamilyPOD *>(mmap.data());
|
||||
if (family_info->format_tag != DB_FORMAT_TAG_CURRENT)
|
||||
log_error("Chipdb %s has wrong format tag\n", family_filename.c_str());
|
||||
|
||||
// Slurp IdStrings.
|
||||
// Entry 0 must be "".
|
||||
NPNR_ASSERT(family_info->idstrings[0].get()[0] == 0);
|
||||
for (int i = 1; i < family_info->num_idstrings; i++)
|
||||
IdString::initialize_add(this, family_info->idstrings[i].get(), i);
|
||||
|
||||
// Make double sure we got the right family.
|
||||
if (IdString(family_info->name_id).str(this) != fname)
|
||||
log_error("Chipdb %s is for strange family\n", family_filename.c_str());
|
||||
|
||||
// Search for the device.
|
||||
int dev_name_id = id(args.device).index;
|
||||
for (int i = 0; i < family_info->num_devices; i++) {
|
||||
if (family_info->devices[i].name_id == dev_name_id) {
|
||||
device_info = family_info->devices[i].device.get();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (device_info == nullptr)
|
||||
log_error("Unknown device.\n");
|
||||
|
||||
// Find the right package.
|
||||
int pkg_name_id = id(args.package).index;
|
||||
if (pkg_name_id == 0) {
|
||||
package_info = &device_info->packages[0];
|
||||
} else {
|
||||
for (int i = 0; i < device_info->num_packages; i++) {
|
||||
if (device_info->packages[i].name_id == pkg_name_id) {
|
||||
package_info = &device_info->packages[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (package_info == nullptr)
|
||||
log_error("Unknown package.\n");
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
BelId Arch::getBelByName(IdString name) const
|
||||
{
|
||||
BelId ret;
|
||||
auto it = bel_by_name.find(name);
|
||||
if (it != bel_by_name.end())
|
||||
return it->second;
|
||||
|
||||
Location loc;
|
||||
std::string basename;
|
||||
std::tie(loc.x, loc.y, basename) = split_identifier_name(name.str(this));
|
||||
ret.location = loc;
|
||||
IdString basename_id = id(basename);
|
||||
auto &tt = getTileType(loc.x, loc.y);
|
||||
for (int i = 0; i < tt.num_bels; i++) {
|
||||
if (tt.bels[i].name_id == basename_id.index) {
|
||||
ret.index = i;
|
||||
bel_by_name[name] = ret;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return BelId();
|
||||
}
|
||||
|
||||
WireId Arch::getBelPinWire(BelId bel, IdString pin) const
|
||||
{
|
||||
WireId ret;
|
||||
|
||||
NPNR_ASSERT(bel != BelId());
|
||||
|
||||
int num_bel_wires = getBelTypeInfo(bel).num_pins;
|
||||
const BelTypePinPOD *bel_type_wires = getBelTypeInfo(bel).pins.get();
|
||||
for (int i = 0; i < num_bel_wires; i++)
|
||||
if (bel_type_wires[i].name_id == pin.index) {
|
||||
ret.location = bel.location;
|
||||
ret.index = getTileTypeBel(bel).pin_wires[i];
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
PortType Arch::getBelPinType(BelId bel, IdString pin) const
|
||||
{
|
||||
NPNR_ASSERT(bel != BelId());
|
||||
|
||||
int num_bel_wires = getBelTypeInfo(bel).num_pins;
|
||||
const BelTypePinPOD *bel_type_wires = getBelTypeInfo(bel).pins.get();
|
||||
for (int i = 0; i < num_bel_wires; i++)
|
||||
if (bel_type_wires[i].name_id == pin.index) {
|
||||
bool is_in = bel_type_wires[i].flags & BelTypePinPOD::FLAG_INPUT;
|
||||
bool is_out = bel_type_wires[i].flags & BelTypePinPOD::FLAG_OUTPUT;
|
||||
if (is_in && is_out)
|
||||
return PORT_INOUT;
|
||||
if (is_in)
|
||||
return PORT_IN;
|
||||
assert(is_out);
|
||||
return PORT_OUT;
|
||||
}
|
||||
|
||||
return PORT_INOUT;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
WireId Arch::getWireByName(IdString name) const
|
||||
{
|
||||
WireId ret;
|
||||
auto it = wire_by_name.find(name);
|
||||
if (it != wire_by_name.end())
|
||||
return it->second;
|
||||
|
||||
Location loc;
|
||||
std::string basename;
|
||||
std::tie(loc.x, loc.y, basename) = split_identifier_name(name.str(this));
|
||||
ret.location = loc;
|
||||
IdString basename_id = id(basename);
|
||||
auto &tt = getTileType(loc.x, loc.y);
|
||||
for (int i = 0; i < tt.num_wires; i++) {
|
||||
if (tt.wires[i].name_id == basename_id.index) {
|
||||
ret.index = i;
|
||||
wire_by_name[name] = ret;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return WireId();
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
PipId Arch::getPipByName(IdString name) const
|
||||
{
|
||||
auto it = pip_by_name.find(name);
|
||||
if (it != pip_by_name.end())
|
||||
return it->second;
|
||||
|
||||
PipId ret;
|
||||
Location loc;
|
||||
std::string basename;
|
||||
std::tie(loc.x, loc.y, basename) = split_identifier_name(name.str(this));
|
||||
ret.location = loc;
|
||||
AllPipRange range;
|
||||
range.b.cursor_tile = loc.x + device_info->width * loc.y;
|
||||
range.b.cursor_kind = PIP_KIND_PIP;
|
||||
range.b.cursor_index = 0;
|
||||
range.b.cursor_subindex = -1;
|
||||
range.b.device = device_info;
|
||||
range.b.family = family_info;
|
||||
++range.b;
|
||||
range.e.cursor_tile = loc.x + device_info->width * loc.y + 1;
|
||||
range.e.cursor_kind = PIP_KIND_PIP;
|
||||
range.e.cursor_index = 0;
|
||||
range.e.cursor_subindex = -1;
|
||||
range.e.device = device_info;
|
||||
range.e.family = family_info;
|
||||
++range.e;
|
||||
for (const auto& curr: range) {
|
||||
pip_by_name[getPipName(curr)] = curr;
|
||||
}
|
||||
if (pip_by_name.find(name) == pip_by_name.end())
|
||||
NPNR_ASSERT_FALSE_STR("no pip named " + name.str(this));
|
||||
return pip_by_name[name];
|
||||
}
|
||||
|
||||
IdString Arch::getPipName(PipId pip) const
|
||||
{
|
||||
NPNR_ASSERT(pip != PipId());
|
||||
|
||||
int x = pip.location.x;
|
||||
int y = pip.location.y;
|
||||
|
||||
if (pip.kind == PIP_KIND_PIP) {
|
||||
std::string src_name = getWireBasename(getPipSrcWire(pip)).str(this);
|
||||
std::string dst_name = getWireBasename(getPipDstWire(pip)).str(this);
|
||||
return id("X" + std::to_string(x) + "/Y" + std::to_string(y) + "/" + src_name + ".->." + dst_name);
|
||||
} else {
|
||||
auto &tt = getTileType(pip.location);
|
||||
std::string port_name = IdString(tt.ports[pip.index].name_id).str(this);
|
||||
std::string dst_name = getWireBasename(getPipDstWire(pip)).str(this);
|
||||
return id("X" + std::to_string(x) + "/Y" + std::to_string(y) + "/" + port_name + "/" + std::to_string(pip.subindex) + ".->." + dst_name);
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
void PipIterator::operator++() {
|
||||
cursor_index++;
|
||||
auto &ttw = arch->getTileTypeWire(wire);
|
||||
if (stage == STAGE_PIPS) {
|
||||
int num;
|
||||
if (mode == MODE_UPHILL)
|
||||
num = ttw.num_pip_dst_xrefs;
|
||||
else
|
||||
num = ttw.num_pip_src_xrefs;
|
||||
if (cursor_index == num) {
|
||||
cursor_index = 0;
|
||||
stage = STAGE_PORTS;
|
||||
}
|
||||
}
|
||||
if (stage == STAGE_PORTS) {
|
||||
while (true) {
|
||||
if (cursor_index == ttw.num_port_xrefs) {
|
||||
cursor_index = 0;
|
||||
stage = STAGE_END;
|
||||
break;
|
||||
}
|
||||
// Make sure the port is connected.
|
||||
auto &tile = arch->getTile(wire.location);
|
||||
auto &xref = ttw.port_xrefs[cursor_index];
|
||||
auto &conn = tile.conns[xref.port_idx];
|
||||
if (conn.port_idx != -1) {
|
||||
// Make sure the wire in a port is connected.
|
||||
Location other_loc;
|
||||
other_loc.x = conn.tile_x;
|
||||
other_loc.y = conn.tile_y;
|
||||
auto &other_tt = arch->getTileType(other_loc);
|
||||
if (other_tt.ports[conn.port_idx].wires[xref.wire_idx] != -1)
|
||||
break;
|
||||
}
|
||||
cursor_index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PipId PipIterator::operator*() const {
|
||||
PipId ret;
|
||||
auto &ttw = arch->getTileTypeWire(wire);
|
||||
ret.location = wire.location;
|
||||
if (mode == MODE_UPHILL) {
|
||||
if (stage == STAGE_PIPS) {
|
||||
ret.kind = PIP_KIND_PIP;
|
||||
ret.index = ttw.pip_dst_xrefs[cursor_index];
|
||||
} else {
|
||||
ret.kind = PIP_KIND_PORT;
|
||||
auto &xref = ttw.port_xrefs[cursor_index];
|
||||
ret.index = xref.port_idx;
|
||||
ret.subindex = xref.wire_idx;
|
||||
}
|
||||
} else {
|
||||
if (stage == STAGE_PIPS) {
|
||||
ret.kind = PIP_KIND_PIP;
|
||||
ret.index = ttw.pip_src_xrefs[cursor_index];
|
||||
} else {
|
||||
ret.kind = PIP_KIND_PORT;
|
||||
auto &tile = arch->getTile(wire.location);
|
||||
auto &xref = ttw.port_xrefs[cursor_index];
|
||||
auto &conn = tile.conns[xref.port_idx];
|
||||
ret.location.x = conn.tile_x;
|
||||
ret.location.y = conn.tile_y;
|
||||
ret.index = conn.port_idx;
|
||||
ret.subindex = xref.wire_idx;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
//
|
||||
// XXX package pins
|
||||
|
||||
std::vector<IdString> Arch::getBelPins(BelId bel) const
|
||||
{
|
||||
std::vector<IdString> ret;
|
||||
NPNR_ASSERT(bel != BelId());
|
||||
|
||||
int num_bel_wires = getBelTypeInfo(bel).num_pins;
|
||||
const BelTypePinPOD *bel_type_wires = getBelTypeInfo(bel).pins.get();
|
||||
|
||||
for (int i = 0; i < num_bel_wires; i++) {
|
||||
IdString id;
|
||||
id.index = bel_type_wires[i].name_id;
|
||||
ret.push_back(id);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
delay_t Arch::estimateDelay(WireId src, WireId dst) const
|
||||
{
|
||||
// TODO
|
||||
return 13;
|
||||
}
|
||||
|
||||
delay_t Arch::predictDelay(const NetInfo *net_info, const PortRef &sink) const
|
||||
{
|
||||
// TODO
|
||||
return 13;
|
||||
}
|
||||
|
||||
bool Arch::getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const { return false; }
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
bool Arch::place() { return placer1(getCtx(), Placer1Cfg(getCtx())); }
|
||||
|
||||
bool Arch::route() { return router1(getCtx(), Router1Cfg(getCtx())); }
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
std::vector<GraphicElement> Arch::getDecalGraphics(DecalId decal) const
|
||||
{
|
||||
std::vector<GraphicElement> ret;
|
||||
|
||||
if (decal.type == DecalId::TYPE_BEL) {
|
||||
BelId bel;
|
||||
bel.index = decal.z;
|
||||
bel.location = decal.location;
|
||||
int max_z = getTileBelDimZ(bel.location.x, bel.location.y);
|
||||
int z = bel.index;
|
||||
//auto bel_type = getBelType(bel);
|
||||
|
||||
GraphicElement el;
|
||||
el.type = GraphicElement::TYPE_BOX;
|
||||
el.style = decal.active ? GraphicElement::STYLE_ACTIVE : GraphicElement::STYLE_INACTIVE;
|
||||
el.x1 = bel.location.x + 0.05;
|
||||
el.x2 = bel.location.x + 0.95;
|
||||
el.y1 = bel.location.y + (z + 0.05) / max_z;
|
||||
el.y2 = bel.location.y + (z + 0.95) / max_z;
|
||||
ret.push_back(el);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
DecalXY Arch::getBelDecal(BelId bel) const
|
||||
{
|
||||
DecalXY decalxy;
|
||||
decalxy.decal.type = DecalId::TYPE_BEL;
|
||||
decalxy.decal.location = bel.location;
|
||||
decalxy.decal.z = bel.index;
|
||||
decalxy.decal.active = !checkBelAvail(bel);
|
||||
return decalxy;
|
||||
}
|
||||
|
||||
DecalXY Arch::getWireDecal(WireId wire) const { return {}; }
|
||||
|
||||
DecalXY Arch::getPipDecal(PipId pip) const { return {}; };
|
||||
|
||||
DecalXY Arch::getGroupDecal(GroupId pip) const { return {}; };
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort, DelayInfo &delay) const
|
||||
{
|
||||
// XXX
|
||||
delay.min_delay = 11;
|
||||
delay.max_delay = 13;
|
||||
return true;
|
||||
}
|
||||
|
||||
TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, int &clockInfoCount) const
|
||||
{
|
||||
// XXX
|
||||
return TMG_IGNORE;
|
||||
}
|
||||
|
||||
TimingClockingInfo Arch::getPortClockingInfo(const CellInfo *cell, IdString port, int index) const
|
||||
{
|
||||
TimingClockingInfo info;
|
||||
info.setup = getDelayFromNS(0);
|
||||
info.hold = getDelayFromNS(0);
|
||||
info.clockToQ = getDelayFromNS(0);
|
||||
// XXX
|
||||
return info;
|
||||
}
|
||||
|
||||
NEXTPNR_NAMESPACE_END
|
1182
leuctra/arch.h
Normal file
1182
leuctra/arch.h
Normal file
File diff suppressed because it is too large
Load Diff
42
leuctra/arch_pybindings.cc
Normal file
42
leuctra/arch_pybindings.cc
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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 "arch_pybindings.h"
|
||||
#include "nextpnr.h"
|
||||
#include "pybindings.h"
|
||||
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
void arch_wrap_python()
|
||||
{
|
||||
using namespace PythonConversion;
|
||||
auto arch_cls = class_<Arch, Arch *, bases<BaseCtx>, boost::noncopyable>("Arch", init<ArchArgs>());
|
||||
auto ctx_cls = class_<Context, Context *, bases<Arch>, boost::noncopyable>("Context", no_init)
|
||||
.def("checksum", &Context::checksum)
|
||||
.def("pack", &Context::pack)
|
||||
.def("place", &Context::place)
|
||||
.def("route", &Context::route);
|
||||
}
|
||||
|
||||
NEXTPNR_NAMESPACE_END
|
||||
|
||||
#endif
|
83
leuctra/arch_pybindings.h
Normal file
83
leuctra/arch_pybindings.h
Normal file
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
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<WireId>
|
||||
{
|
||||
WireId from_str(Context *ctx, std::string name) { return ctx->getWireByName(ctx->id(name)); }
|
||||
|
||||
std::string to_str(Context *ctx, WireId id)
|
||||
{
|
||||
if (id == WireId())
|
||||
throw bad_wrap();
|
||||
return ctx->getWireName(id).str(ctx);
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct string_converter<const WireId>
|
||||
{
|
||||
WireId from_str(Context *ctx, std::string name) { return ctx->getWireByName(ctx->id(name)); }
|
||||
|
||||
std::string to_str(Context *ctx, WireId id)
|
||||
{
|
||||
if (id == WireId())
|
||||
throw bad_wrap();
|
||||
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)
|
||||
{
|
||||
if (id == PipId())
|
||||
throw bad_wrap();
|
||||
return ctx->getPipName(id).str(ctx);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace PythonConversion
|
||||
|
||||
NEXTPNR_NAMESPACE_END
|
||||
#endif
|
||||
#endif
|
234
leuctra/archdefs.h
Normal file
234
leuctra/archdefs.h
Normal file
@ -0,0 +1,234 @@
|
||||
/*
|
||||
* nextpnr -- Next Generation Place and Route
|
||||
*
|
||||
* Copyright (C) 2018 David Shah <david@symbioticeda.com>
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef NEXTPNR_H
|
||||
#error Include "archdefs.h" via "nextpnr.h" only.
|
||||
#endif
|
||||
|
||||
#include <boost/functional/hash.hpp>
|
||||
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
typedef int delay_t;
|
||||
|
||||
struct DelayInfo
|
||||
{
|
||||
delay_t min_delay = 0, max_delay = 0;
|
||||
|
||||
delay_t minRaiseDelay() const { return min_delay; }
|
||||
delay_t maxRaiseDelay() const { return max_delay; }
|
||||
|
||||
delay_t minFallDelay() const { return min_delay; }
|
||||
delay_t maxFallDelay() const { return max_delay; }
|
||||
|
||||
delay_t minDelay() const { return min_delay; }
|
||||
delay_t maxDelay() const { return max_delay; }
|
||||
|
||||
DelayInfo operator+(const DelayInfo &other) const
|
||||
{
|
||||
DelayInfo ret;
|
||||
ret.min_delay = this->min_delay + other.min_delay;
|
||||
ret.max_delay = this->max_delay + other.max_delay;
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
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; }
|
||||
bool operator<(const Location &other) const { return y == other.y ? x < other.x : y < other.y; }
|
||||
};
|
||||
|
||||
inline Location operator+(const Location &a, const Location &b) { return Location(a.x + b.x, a.y + b.y); }
|
||||
|
||||
struct BelId
|
||||
{
|
||||
Location location;
|
||||
int32_t index = -1;
|
||||
|
||||
bool operator==(const BelId &other) const { return index == other.index && location == other.location; }
|
||||
bool operator!=(const BelId &other) const { return index != other.index || location != other.location; }
|
||||
bool operator<(const BelId &other) const
|
||||
{
|
||||
return location == other.location ? index < other.index : location < other.location;
|
||||
}
|
||||
};
|
||||
|
||||
struct WireId
|
||||
{
|
||||
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 WireId &other) const
|
||||
{
|
||||
return location == other.location ? index < other.index : location < other.location;
|
||||
}
|
||||
};
|
||||
|
||||
enum PipKind {
|
||||
PIP_KIND_PIP,
|
||||
PIP_KIND_PORT,
|
||||
};
|
||||
|
||||
struct PipId
|
||||
{
|
||||
Location location;
|
||||
// Is it a plain pip, or a pseudo-pip for a port.
|
||||
PipKind kind;
|
||||
// Index of the pip or the port.
|
||||
int32_t index = -1;
|
||||
// For ports, index of the wire in the port.
|
||||
int32_t subindex = -1;
|
||||
|
||||
bool operator==(const PipId &other) const { return subindex == other.subindex && index == other.index && kind == other.kind && location == other.location; }
|
||||
bool operator!=(const PipId &other) const { return subindex != other.subindex || index != other.index || kind != other.kind || location != other.location; }
|
||||
bool operator<(const PipId &other) const
|
||||
{
|
||||
if (location != other.location)
|
||||
return location < other.location;
|
||||
if (kind != other.kind)
|
||||
return kind < other.kind;
|
||||
if (index != other.index)
|
||||
return index < other.index;
|
||||
return subindex < other.subindex;
|
||||
}
|
||||
};
|
||||
|
||||
struct GroupId
|
||||
{
|
||||
int32_t index = -1;
|
||||
|
||||
bool operator==(const GroupId &other) const { return index == other.index; }
|
||||
bool operator!=(const GroupId &other) const { return index != other.index; }
|
||||
};
|
||||
|
||||
struct DecalId
|
||||
{
|
||||
enum
|
||||
{
|
||||
TYPE_NONE,
|
||||
TYPE_BEL
|
||||
} type;
|
||||
Location location;
|
||||
uint32_t z = 0;
|
||||
bool active = false;
|
||||
bool operator==(const DecalId &other) const
|
||||
{
|
||||
return type == other.type && location == other.location && z == other.z && active == other.active;
|
||||
}
|
||||
bool operator!=(const DecalId &other) const
|
||||
{
|
||||
return type != other.type || location != other.location || z != other.z || active != other.active;
|
||||
}
|
||||
};
|
||||
|
||||
struct ArchNetInfo
|
||||
{
|
||||
bool is_global = false;
|
||||
};
|
||||
|
||||
struct ArchCellInfo
|
||||
{
|
||||
struct
|
||||
{
|
||||
bool using_dff;
|
||||
bool has_l6mux;
|
||||
IdString clk_sig, lsr_sig, clkmux, lsrmux, srmode;
|
||||
} sliceInfo;
|
||||
};
|
||||
|
||||
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
|
||||
{
|
||||
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
|
||||
{
|
||||
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
|
||||
{
|
||||
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 GroupId>
|
||||
{
|
||||
std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX GroupId &group) const noexcept
|
||||
{
|
||||
return std::hash<int>()(group.index);
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct hash<NEXTPNR_NAMESPACE_PREFIX DecalId>
|
||||
{
|
||||
std::size_t operator()(const NEXTPNR_NAMESPACE_PREFIX DecalId &decal) const noexcept
|
||||
{
|
||||
std::size_t seed = 0;
|
||||
boost::hash_combine(seed, hash<int>()(decal.type));
|
||||
boost::hash_combine(seed, hash<NEXTPNR_NAMESPACE_PREFIX Location>()(decal.location));
|
||||
boost::hash_combine(seed, hash<int>()(decal.z));
|
||||
boost::hash_combine(seed, hash<bool>()(decal.active));
|
||||
return seed;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace std
|
0
leuctra/family.cmake
Normal file
0
leuctra/family.cmake
Normal file
75
leuctra/main.cc
Normal file
75
leuctra/main.cc
Normal file
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
#include <fstream>
|
||||
#include "command.h"
|
||||
#include "design_utils.h"
|
||||
#include "log.h"
|
||||
#include "timing.h"
|
||||
|
||||
USING_NEXTPNR_NAMESPACE
|
||||
|
||||
class LeuctraCommandHandler : public CommandHandler
|
||||
{
|
||||
public:
|
||||
LeuctraCommandHandler(int argc, char **argv);
|
||||
virtual ~LeuctraCommandHandler(){};
|
||||
std::unique_ptr<Context> createContext() override;
|
||||
void setupArchContext(Context *ctx) override{};
|
||||
void customBitstream(Context *ctx) override;
|
||||
|
||||
protected:
|
||||
po::options_description getArchOptions() override;
|
||||
};
|
||||
|
||||
LeuctraCommandHandler::LeuctraCommandHandler(int argc, char **argv) : CommandHandler(argc, argv) {}
|
||||
|
||||
po::options_description LeuctraCommandHandler::getArchOptions()
|
||||
{
|
||||
po::options_description specific("Architecture specific options");
|
||||
specific.add_options()("device", po::value<std::string>(), "select device");
|
||||
specific.add_options()("package", po::value<std::string>(), "select device package");
|
||||
specific.add_options()("speed", po::value<std::string>(), "select device speedgrade");
|
||||
return specific;
|
||||
}
|
||||
|
||||
void LeuctraCommandHandler::customBitstream(Context *ctx) { log_error("Here is when bitstream gets created"); }
|
||||
|
||||
std::unique_ptr<Context> LeuctraCommandHandler::createContext()
|
||||
{
|
||||
if (vm.count("device"))
|
||||
chipArgs.device = vm["device"].as<std::string>();
|
||||
else
|
||||
chipArgs.device = "xc6slx9";
|
||||
if (vm.count("package"))
|
||||
chipArgs.package = vm["package"].as<std::string>();
|
||||
if (vm.count("speed"))
|
||||
chipArgs.speed = vm["speed"].as<std::string>();
|
||||
return std::unique_ptr<Context>(new Context(chipArgs));
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
LeuctraCommandHandler handler(argc, argv);
|
||||
return handler.exec();
|
||||
}
|
||||
|
||||
#endif
|
31
leuctra/pack.cc
Normal file
31
leuctra/pack.cc
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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "nextpnr.h"
|
||||
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
// Main pack function
|
||||
bool Arch::pack()
|
||||
{
|
||||
// XXX
|
||||
return true;
|
||||
}
|
||||
|
||||
NEXTPNR_NAMESPACE_END
|
47
leuctra/project.cc
Normal file
47
leuctra/project.cc
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* nextpnr -- Next Generation Place and Route
|
||||
*
|
||||
* Copyright (C) 2018 Miodrag Milanovic <miodrag@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 "project.h"
|
||||
#include <boost/filesystem/convenience.hpp>
|
||||
#include <boost/property_tree/json_parser.hpp>
|
||||
#include <fstream>
|
||||
#include "log.h"
|
||||
|
||||
NEXTPNR_NAMESPACE_BEGIN
|
||||
|
||||
void ProjectHandler::saveArch(Context *ctx, pt::ptree &root, std::string path)
|
||||
{
|
||||
root.put("project.arch.package", ctx->archArgs().package);
|
||||
root.put("project.arch.speed", ctx->archArgs().speed);
|
||||
}
|
||||
|
||||
std::unique_ptr<Context> ProjectHandler::createContext(pt::ptree &root)
|
||||
{
|
||||
ArchArgs chipArgs;
|
||||
chipArgs.device = root.get<std::string>("project.arch.type");
|
||||
chipArgs.package = root.get<std::string>("project.arch.package");
|
||||
chipArgs.speed = root.get<std::string>("project.arch.speed");
|
||||
|
||||
return std::unique_ptr<Context>(new Context(chipArgs));
|
||||
}
|
||||
|
||||
void ProjectHandler::loadArch(Context *ctx, pt::ptree &root, std::string path) {}
|
||||
|
||||
NEXTPNR_NAMESPACE_END
|
||||
|
Loading…
Reference in New Issue
Block a user