This commit is contained in:
Marcin Kościelnicki 2019-02-19 16:40:20 +01:00 committed by Marcin Kościelnicki
parent a0091eb44b
commit 048bae1d85
15 changed files with 2355 additions and 2 deletions

View File

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

View File

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

51
gui/leuctra/mainwindow.cc Normal file
View 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
View 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
View File

@ -0,0 +1,2 @@
<RCC>
</RCC>

556
leuctra/arch.cc Normal file
View 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

File diff suppressed because it is too large Load Diff

View 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
View 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
View 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
View File

75
leuctra/main.cc Normal file
View 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
View 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
View 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