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() endif()
# List of families to build # 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(ARCH "" CACHE STRING "Architecture family for nextpnr build")
set_property(CACHE ARCH PROPERTY STRINGS ${FAMILIES}) set_property(CACHE ARCH PROPERTY STRINGS ${FAMILIES})
@ -67,6 +67,11 @@ foreach(item ${ARCH})
if (NOT item IN_LIST FAMILIES) if (NOT item IN_LIST FAMILIES)
message(FATAL_ERROR "Architecture '${item}' not in list of supported architectures") message(FATAL_ERROR "Architecture '${item}' not in list of supported architectures")
endif() endif()
if (item STREQUAL "leuctra")
if (NOT EXTERNAL_CHIPDB)
message(FATAL_ERROR "The leuctra backend requires setting -DEXTERNAL_CHIPDB=ON")
endif()
endif()
endforeach() endforeach()
set(CMAKE_CXX_STANDARD 11) 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); wireMap[std::pair<int, int>(wire->x, wire->y)].push_back(wireid);
} }
#endif #endif
#ifdef ARCH_ECP5 #if defined(ARCH_ECP5) || defined(ARCH_LEUCTRA)
for (const auto &wire : ctx->getWires()) { for (const auto &wire : ctx->getWires()) {
wireMap[std::pair<int, int>(wire.location.x, wire.location.y)].push_back(wire); 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