Merge branch 'master' into shadowram
This commit is contained in:
commit
0641ff47d9
@ -145,7 +145,8 @@ An example of how to use the generic flow is in [generic/examples](generic/examp
|
|||||||
|
|
||||||
The nextpnr GUI is not built by default, to reduce the number of dependencies for a standard headless build. To enable it, add `-DBUILD_GUI=ON` to the CMake command line and ensure that Qt5 and OpenGL are available:
|
The nextpnr GUI is not built by default, to reduce the number of dependencies for a standard headless build. To enable it, add `-DBUILD_GUI=ON` to the CMake command line and ensure that Qt5 and OpenGL are available:
|
||||||
|
|
||||||
- On Ubuntu, install `qt5-default`
|
- On Ubuntu 22.04 LTS, install `qtcreator qtbase5-dev qt5-qmake`
|
||||||
|
- On other Ubuntu versions, install `qt5-default`
|
||||||
- For MSVC vcpkg, install `qt5-base` (32-bit) or `qt5-base:x64-windows` (64-bit)
|
- For MSVC vcpkg, install `qt5-base` (32-bit) or `qt5-base:x64-windows` (64-bit)
|
||||||
- For Homebrew, install `qt5` and add qt5 in path: `echo 'export PATH="/usr/local/opt/qt/bin:$PATH"' >> ~/.bash_profile`
|
- For Homebrew, install `qt5` and add qt5 in path: `echo 'export PATH="/usr/local/opt/qt/bin:$PATH"' >> ~/.bash_profile`
|
||||||
` - this change is effective in next terminal session, so please re-open terminal window before building
|
` - this change is effective in next terminal session, so please re-open terminal window before building
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#ifndef NO_PYTHON
|
#ifndef NO_PYTHON
|
||||||
|
|
||||||
#include "arch_pybindings.h"
|
#include "arch_pybindings.h"
|
||||||
|
#include "bitstream.h"
|
||||||
#include "nextpnr.h"
|
#include "nextpnr.h"
|
||||||
#include "pybindings.h"
|
#include "pybindings.h"
|
||||||
|
|
||||||
@ -69,6 +70,8 @@ void arch_wrap_python(py::module &m)
|
|||||||
WRAP_MAP_UPTR(m, CellMap, "IdCellMap");
|
WRAP_MAP_UPTR(m, CellMap, "IdCellMap");
|
||||||
WRAP_MAP_UPTR(m, NetMap, "IdNetMap");
|
WRAP_MAP_UPTR(m, NetMap, "IdNetMap");
|
||||||
WRAP_MAP(m, HierarchyMap, wrap_context<HierarchicalCell &>, "HierarchyMap");
|
WRAP_MAP(m, HierarchyMap, wrap_context<HierarchicalCell &>, "HierarchyMap");
|
||||||
|
|
||||||
|
m.def("write_bitstream", &write_bitstream);
|
||||||
}
|
}
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_END
|
NEXTPNR_NAMESPACE_END
|
||||||
|
224
gowin/arch.cc
224
gowin/arch.cc
@ -19,6 +19,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <boost/algorithm/string.hpp>
|
#include <boost/algorithm/string.hpp>
|
||||||
|
#include <cells.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <regex>
|
#include <regex>
|
||||||
@ -33,6 +34,8 @@
|
|||||||
|
|
||||||
NEXTPNR_NAMESPACE_BEGIN
|
NEXTPNR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
|
const PairPOD *pairLookup(const PairPOD *list, const size_t len, const int dest);
|
||||||
|
|
||||||
// GUI
|
// GUI
|
||||||
void Arch::fixClockSpineDecals(void)
|
void Arch::fixClockSpineDecals(void)
|
||||||
{
|
{
|
||||||
@ -175,6 +178,145 @@ DecalXY Arch::getWireDecal(WireId wire) const
|
|||||||
return wires.at(wire).decalxy_active;
|
return wires.at(wire).decalxy_active;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Arch::allocate_longwire(NetInfo *ni, int lw_idx)
|
||||||
|
{
|
||||||
|
NPNR_ASSERT(ni != nullptr);
|
||||||
|
if (ni->driver.cell == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (ni->name == id("$PACKER_VCC_NET") || ni->name == id("$PACKER_GND_NET")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// So far only for OBUF
|
||||||
|
switch (ni->driver.cell->type.index) {
|
||||||
|
case ID_ODDR: /* fall-through*/
|
||||||
|
case ID_ODDRC: /* fall-through*/
|
||||||
|
case ID_IOBUF: /* fall-through*/
|
||||||
|
case ID_TBUF:
|
||||||
|
return false;
|
||||||
|
case ID_OBUF:
|
||||||
|
if (getCtx()->debug) {
|
||||||
|
log_info("Long wire for IO %s\n", nameOf(ni));
|
||||||
|
}
|
||||||
|
ni = ni->driver.cell->ports.at(id_I).net;
|
||||||
|
return allocate_longwire(ni, lw_idx);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getCtx()->debug) {
|
||||||
|
log_info("Requested index:%d\n", lw_idx);
|
||||||
|
}
|
||||||
|
if (avail_longwires == 0 || (lw_idx != -1 && (avail_longwires & (1 << lw_idx)) == 0)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int longwire = lw_idx;
|
||||||
|
if (lw_idx == -1) {
|
||||||
|
for (longwire = 7; longwire >= 0; --longwire) {
|
||||||
|
if (avail_longwires & (1 << longwire)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
avail_longwires &= ~(1 << longwire);
|
||||||
|
|
||||||
|
// BUFS cell
|
||||||
|
CellInfo *bufs;
|
||||||
|
char buf[40];
|
||||||
|
snprintf(buf, sizeof(buf), "$PACKER_BUFS%d", longwire);
|
||||||
|
std::unique_ptr<CellInfo> new_cell = create_generic_cell(getCtx(), id_BUFS, buf);
|
||||||
|
bufs = new_cell.get();
|
||||||
|
cells[bufs->name] = std::move(new_cell);
|
||||||
|
if (lw_idx != -1) {
|
||||||
|
bufs->cluster = bufs->name;
|
||||||
|
bufs->constr_z = lw_idx + BelZ::bufs_0_z;
|
||||||
|
bufs->constr_abs_z = true;
|
||||||
|
bufs->constr_children.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
// old driver -> bufs LW input net
|
||||||
|
snprintf(buf, sizeof(buf), "$PACKER_BUFS_%c", longwire + 'A');
|
||||||
|
auto net = std::make_unique<NetInfo>(id(buf));
|
||||||
|
NetInfo *bufs_net = net.get();
|
||||||
|
nets[net->name] = std::move(net);
|
||||||
|
|
||||||
|
// split the net
|
||||||
|
CellInfo *driver_cell = ni->driver.cell;
|
||||||
|
IdString driver_port = ni->driver.port;
|
||||||
|
driver_cell->disconnectPort(driver_port);
|
||||||
|
|
||||||
|
bufs->connectPort(id_O, ni);
|
||||||
|
bufs->connectPort(id_I, bufs_net);
|
||||||
|
driver_cell->connectPort(driver_port, bufs_net);
|
||||||
|
|
||||||
|
if (getCtx()->debug) {
|
||||||
|
log_info("Long wire %d was allocated\n", longwire);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Arch::fix_longwire_bels()
|
||||||
|
{
|
||||||
|
// After routing, it is clear which wires and in which bus SS00 and SS40 are used and
|
||||||
|
// in which quadrant they are routed. Here we write it in the attributes.
|
||||||
|
for (auto &cell : cells) {
|
||||||
|
CellInfo *ci = cell.second.get();
|
||||||
|
if (ci->type != id_BUFS) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const NetInfo *ni = ci->getPort(id_O);
|
||||||
|
if (ni == nullptr) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// bus wire is one of the wires
|
||||||
|
// value does not matter, but the L/R parameter itself
|
||||||
|
for (auto &wire : ni->wires) {
|
||||||
|
WireId w = wires[wire.first].type;
|
||||||
|
switch (w.hash()) {
|
||||||
|
case ID_LWSPINETL0:
|
||||||
|
case ID_LWSPINETL1:
|
||||||
|
case ID_LWSPINETL2:
|
||||||
|
case ID_LWSPINETL3:
|
||||||
|
case ID_LWSPINETL4:
|
||||||
|
case ID_LWSPINETL5:
|
||||||
|
case ID_LWSPINETL6:
|
||||||
|
case ID_LWSPINETL7:
|
||||||
|
case ID_LWSPINEBL0:
|
||||||
|
case ID_LWSPINEBL1:
|
||||||
|
case ID_LWSPINEBL2:
|
||||||
|
case ID_LWSPINEBL3:
|
||||||
|
case ID_LWSPINEBL4:
|
||||||
|
case ID_LWSPINEBL5:
|
||||||
|
case ID_LWSPINEBL6:
|
||||||
|
case ID_LWSPINEBL7:
|
||||||
|
ci->setParam(id("L"), Property(w.str(this)));
|
||||||
|
break;
|
||||||
|
case ID_LWSPINETR0:
|
||||||
|
case ID_LWSPINETR1:
|
||||||
|
case ID_LWSPINETR2:
|
||||||
|
case ID_LWSPINETR3:
|
||||||
|
case ID_LWSPINETR4:
|
||||||
|
case ID_LWSPINETR5:
|
||||||
|
case ID_LWSPINETR6:
|
||||||
|
case ID_LWSPINETR7:
|
||||||
|
case ID_LWSPINEBR0:
|
||||||
|
case ID_LWSPINEBR1:
|
||||||
|
case ID_LWSPINEBR2:
|
||||||
|
case ID_LWSPINEBR3:
|
||||||
|
case ID_LWSPINEBR4:
|
||||||
|
case ID_LWSPINEBR5:
|
||||||
|
case ID_LWSPINEBR6:
|
||||||
|
case ID_LWSPINEBR7:
|
||||||
|
ci->setParam(id("R"), Property(w.str(this)));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
WireInfo &Arch::wire_info(IdString wire)
|
WireInfo &Arch::wire_info(IdString wire)
|
||||||
{
|
{
|
||||||
auto w = wires.find(wire);
|
auto w = wires.find(wire);
|
||||||
@ -487,7 +629,15 @@ IdString Arch::wireToGlobal(int &row, int &col, const DatabasePOD *db, IdString
|
|||||||
}
|
}
|
||||||
snprintf(buf, 32, "%c%d0", direction, num);
|
snprintf(buf, 32, "%c%d0", direction, num);
|
||||||
wire = id(buf);
|
wire = id(buf);
|
||||||
snprintf(buf, 32, "R%dC%d_%c%d", row + 1, col + 1, direction, num);
|
// local aliases
|
||||||
|
const TilePOD *tile = db->grid[row * db->cols + col].get();
|
||||||
|
auto local_alias = pairLookup(tile->aliases.get(), tile->num_aliases, wire.index);
|
||||||
|
if (local_alias != nullptr) {
|
||||||
|
wire = IdString(local_alias->src_id);
|
||||||
|
snprintf(buf, 32, "R%dC%d_%s", row + 1, col + 1, wire.c_str(this));
|
||||||
|
} else {
|
||||||
|
snprintf(buf, 32, "R%dC%d_%c%d", row + 1, col + 1, direction, num);
|
||||||
|
}
|
||||||
return id(buf);
|
return id(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -628,6 +778,28 @@ DelayQuad Arch::getWireTypeDelay(IdString wire)
|
|||||||
case ID_W830:
|
case ID_W830:
|
||||||
len = id_X8;
|
len = id_X8;
|
||||||
break;
|
break;
|
||||||
|
case ID_LT02:
|
||||||
|
case ID_LT13:
|
||||||
|
glbsrc = id_SPINE_TAP_SCLK_0;
|
||||||
|
break;
|
||||||
|
case ID_LT01:
|
||||||
|
case ID_LT04:
|
||||||
|
glbsrc = id_SPINE_TAP_SCLK_1;
|
||||||
|
break;
|
||||||
|
case ID_LBO0:
|
||||||
|
case ID_LBO1:
|
||||||
|
glbsrc = id_TAP_BRANCH_SCLK;
|
||||||
|
break;
|
||||||
|
case ID_LB01:
|
||||||
|
case ID_LB11:
|
||||||
|
case ID_LB21:
|
||||||
|
case ID_LB31:
|
||||||
|
case ID_LB41:
|
||||||
|
case ID_LB51:
|
||||||
|
case ID_LB61:
|
||||||
|
case ID_LB71:
|
||||||
|
glbsrc = id_BRANCH_SCLK;
|
||||||
|
break;
|
||||||
case ID_GT00:
|
case ID_GT00:
|
||||||
case ID_GT10:
|
case ID_GT10:
|
||||||
glbsrc = id_SPINE_TAP_PCLK;
|
glbsrc = id_SPINE_TAP_PCLK;
|
||||||
@ -647,7 +819,9 @@ DelayQuad Arch::getWireTypeDelay(IdString wire)
|
|||||||
glbsrc = id_BRANCH_PCLK;
|
glbsrc = id_BRANCH_PCLK;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (wire.str(this).rfind("SPINE", 0) == 0) {
|
if (wire.str(this).rfind("LWSPINE", 0) == 0) {
|
||||||
|
glbsrc = IdString(ID_CENT_SPINE_SCLK);
|
||||||
|
} else if (wire.str(this).rfind("SPINE", 0) == 0) {
|
||||||
glbsrc = IdString(ID_CENT_SPINE_PCLK);
|
glbsrc = IdString(ID_CENT_SPINE_PCLK);
|
||||||
} else if (wire.str(this).rfind("UNK", 0) == 0) {
|
} else if (wire.str(this).rfind("UNK", 0) == 0) {
|
||||||
glbsrc = IdString(ID_PIO_CENT_PCLK);
|
glbsrc = IdString(ID_PIO_CENT_PCLK);
|
||||||
@ -691,7 +865,7 @@ void Arch::read_cst(std::istream &in)
|
|||||||
std::regex port_attrre = std::regex("([^ =;]+=[^ =;]+) *([^;]*;)");
|
std::regex port_attrre = std::regex("([^ =;]+=[^ =;]+) *([^;]*;)");
|
||||||
std::regex iobelre = std::regex("IO([TRBL])([0-9]+)\\[?([A-Z])\\]?");
|
std::regex iobelre = std::regex("IO([TRBL])([0-9]+)\\[?([A-Z])\\]?");
|
||||||
std::regex inslocre = std::regex("INS_LOC +\"([^\"]+)\" +R([0-9]+)C([0-9]+)\\[([0-9])\\]\\[([AB])\\] *;.*");
|
std::regex inslocre = std::regex("INS_LOC +\"([^\"]+)\" +R([0-9]+)C([0-9]+)\\[([0-9])\\]\\[([AB])\\] *;.*");
|
||||||
std::regex clockre = std::regex("CLOCK_LOC +\"([^\"]+)\" +BUF([GS])[^;]*;");
|
std::regex clockre = std::regex("CLOCK_LOC +\"([^\"]+)\" +BUF([GS])(\\[([0-7])\\])?[^;]*;.*");
|
||||||
std::smatch match, match_attr, match_pinloc;
|
std::smatch match, match_attr, match_pinloc;
|
||||||
std::string line, pinline;
|
std::string line, pinline;
|
||||||
enum
|
enum
|
||||||
@ -732,15 +906,23 @@ void Arch::read_cst(std::istream &in)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
switch (cst_type) {
|
switch (cst_type) {
|
||||||
case clock: { // CLOCK name BUFG|S
|
case clock: { // CLOCK name BUFG|S=#
|
||||||
std::string which_clock = match[2];
|
std::string which_clock = match[2];
|
||||||
|
std::string lw = match[4];
|
||||||
|
int lw_idx = -1;
|
||||||
|
if (lw.length() > 0) {
|
||||||
|
lw_idx = atoi(lw.c_str());
|
||||||
|
log_info("lw_idx:%d\n", lw_idx);
|
||||||
|
}
|
||||||
if (which_clock.at(0) == 'S') {
|
if (which_clock.at(0) == 'S') {
|
||||||
auto ni = nets.find(net);
|
auto ni = nets.find(net);
|
||||||
if (ni == nets.end()) {
|
if (ni == nets.end()) {
|
||||||
log_info("Net %s not found\n", net.c_str(this));
|
log_info("Net %s not found\n", net.c_str(this));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
log_info("Long wires are not implemented. The %s network will use normal routing.\n", net.c_str(this));
|
if (!allocate_longwire(ni->second.get(), lw_idx)) {
|
||||||
|
log_info("Can't use the long wires. The %s network will use normal routing.\n", net.c_str(this));
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
log_info("BUFG isn't supported\n");
|
log_info("BUFG isn't supported\n");
|
||||||
continue;
|
continue;
|
||||||
@ -1021,6 +1203,31 @@ Arch::Arch(ArchArgs args) : args(args)
|
|||||||
bool dff = true;
|
bool dff = true;
|
||||||
bool oddrc = false;
|
bool oddrc = false;
|
||||||
switch (static_cast<ConstIds>(bel->type_id)) {
|
switch (static_cast<ConstIds>(bel->type_id)) {
|
||||||
|
case ID_BUFS7:
|
||||||
|
z++; /* fall-through*/
|
||||||
|
case ID_BUFS6:
|
||||||
|
z++; /* fall-through*/
|
||||||
|
case ID_BUFS5:
|
||||||
|
z++; /* fall-through*/
|
||||||
|
case ID_BUFS4:
|
||||||
|
z++; /* fall-through*/
|
||||||
|
case ID_BUFS3:
|
||||||
|
z++; /* fall-through*/
|
||||||
|
case ID_BUFS2:
|
||||||
|
z++; /* fall-through*/
|
||||||
|
case ID_BUFS1:
|
||||||
|
z++; /* fall-through*/
|
||||||
|
case ID_BUFS0:
|
||||||
|
snprintf(buf, 32, "R%dC%d_BUFS%d", row + 1, col + 1, z);
|
||||||
|
belname = id(buf);
|
||||||
|
addBel(belname, id_BUFS, Loc(col, row, BelZ::bufs_0_z + z), false);
|
||||||
|
portname = IdString(pairLookup(bel->ports.get(), bel->num_ports, ID_I)->src_id);
|
||||||
|
snprintf(buf, 32, "R%dC%d_%s", row + 1, col + 1, portname.c_str(this));
|
||||||
|
addBelInput(belname, id_I, id(buf));
|
||||||
|
portname = IdString(pairLookup(bel->ports.get(), bel->num_ports, ID_O)->src_id);
|
||||||
|
snprintf(buf, 32, "R%dC%d_%s", row + 1, col + 1, portname.c_str(this));
|
||||||
|
addBelOutput(belname, id_O, id(buf));
|
||||||
|
break;
|
||||||
case ID_GSR0:
|
case ID_GSR0:
|
||||||
snprintf(buf, 32, "R%dC%d_GSR0", row + 1, col + 1);
|
snprintf(buf, 32, "R%dC%d_GSR0", row + 1, col + 1);
|
||||||
belname = id(buf);
|
belname = id(buf);
|
||||||
@ -1324,12 +1531,6 @@ Arch::Arch(ArchArgs args) : args(args)
|
|||||||
snprintf(buf, 32, "R%dC%d_%s_%s", row + 1, col + 1, srcid.c_str(this), destid.c_str(this));
|
snprintf(buf, 32, "R%dC%d_%s_%s", row + 1, col + 1, srcid.c_str(this), destid.c_str(this));
|
||||||
IdString pipname = id(buf);
|
IdString pipname = id(buf);
|
||||||
DelayQuad delay = getWireTypeDelay(destid);
|
DelayQuad delay = getWireTypeDelay(destid);
|
||||||
// local alias
|
|
||||||
auto local_alias = pairLookup(tile->aliases.get(), tile->num_aliases, srcid.index);
|
|
||||||
if (local_alias != nullptr) {
|
|
||||||
srcid = IdString(local_alias->src_id);
|
|
||||||
gsrcname = wireToGlobal(srcrow, srccol, db, srcid);
|
|
||||||
}
|
|
||||||
// global alias
|
// global alias
|
||||||
srcid = IdString(pip.src_id);
|
srcid = IdString(pip.src_id);
|
||||||
GlobalAliasPOD alias;
|
GlobalAliasPOD alias;
|
||||||
@ -1705,6 +1906,7 @@ bool Arch::route()
|
|||||||
}
|
}
|
||||||
getCtx()->settings[id_route] = 1;
|
getCtx()->settings[id_route] = 1;
|
||||||
archInfoToAttributes();
|
archInfoToAttributes();
|
||||||
|
fix_longwire_bels();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
10
gowin/arch.h
10
gowin/arch.h
@ -459,6 +459,9 @@ struct Arch : BaseArch<ArchRanges>
|
|||||||
void assignArchInfo() override;
|
void assignArchInfo() override;
|
||||||
bool cellsCompatible(const CellInfo **cells, int count) const;
|
bool cellsCompatible(const CellInfo **cells, int count) const;
|
||||||
bool haveBelType(int x, int y, IdString bel_type);
|
bool haveBelType(int x, int y, IdString bel_type);
|
||||||
|
bool allocate_longwire(NetInfo *ni, int lw_idx = -1);
|
||||||
|
void fix_longwire_bels();
|
||||||
|
|
||||||
// chip db version
|
// chip db version
|
||||||
unsigned int const chipdb_version = 1;
|
unsigned int const chipdb_version = 1;
|
||||||
|
|
||||||
@ -475,6 +478,9 @@ struct Arch : BaseArch<ArchRanges>
|
|||||||
// XXX GW1NR-9 iobuf quirk
|
// XXX GW1NR-9 iobuf quirk
|
||||||
bool gw1n9_quirk = false;
|
bool gw1n9_quirk = false;
|
||||||
|
|
||||||
|
// 8 Long wires
|
||||||
|
uint8_t avail_longwires = 0xff;
|
||||||
|
|
||||||
// Permissible combinations of modes in a single slice
|
// Permissible combinations of modes in a single slice
|
||||||
std::map<const IdString, IdString> dff_comp_mode;
|
std::map<const IdString, IdString> dff_comp_mode;
|
||||||
};
|
};
|
||||||
@ -488,7 +494,9 @@ enum
|
|||||||
lutram_0_z = 30, // start Z for the IOLOGIC bels
|
lutram_0_z = 30, // start Z for the IOLOGIC bels
|
||||||
vcc_0_z = 277, // virtual VCC bel Z
|
vcc_0_z = 277, // virtual VCC bel Z
|
||||||
gnd_0_z = 278, // virtual VSS bel Z
|
gnd_0_z = 278, // virtual VSS bel Z
|
||||||
osc_z = 280 // Z for the oscillator bels
|
osc_z = 280, // Z for the oscillator bels
|
||||||
|
bufs_0_z = 281, // Z for long wire buffer bel
|
||||||
|
free_z = 289 // Must be the last, one can use z starting from this value, adjust accordingly.
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,6 +77,9 @@ std::unique_ptr<CellInfo> create_generic_cell(Context *ctx, IdString type, std::
|
|||||||
new_cell->addOutput(id_G);
|
new_cell->addOutput(id_G);
|
||||||
} else if (type == id_VCC) {
|
} else if (type == id_VCC) {
|
||||||
new_cell->addOutput(id_V);
|
new_cell->addOutput(id_V);
|
||||||
|
} else if (type == id_BUFS) {
|
||||||
|
new_cell->addInput(id_I);
|
||||||
|
new_cell->addOutput(id_O);
|
||||||
} else {
|
} else {
|
||||||
log_error("unable to create generic cell of type %s\n", type.c_str(ctx));
|
log_error("unable to create generic cell of type %s\n", type.c_str(ctx));
|
||||||
}
|
}
|
||||||
|
@ -679,6 +679,81 @@ X(IOBHS)
|
|||||||
X(IOBIS)
|
X(IOBIS)
|
||||||
X(IOBJS)
|
X(IOBJS)
|
||||||
|
|
||||||
|
// long wires
|
||||||
|
X(BUFS)
|
||||||
|
X(BUFS0)
|
||||||
|
X(BUFS1)
|
||||||
|
X(BUFS2)
|
||||||
|
X(BUFS3)
|
||||||
|
X(BUFS4)
|
||||||
|
X(BUFS5)
|
||||||
|
X(BUFS6)
|
||||||
|
X(BUFS7)
|
||||||
|
X(LWT0)
|
||||||
|
X(LWB0)
|
||||||
|
X(LWT1)
|
||||||
|
X(LWB1)
|
||||||
|
X(LWT2)
|
||||||
|
X(LWB2)
|
||||||
|
X(LWT3)
|
||||||
|
X(LWB3)
|
||||||
|
X(LWT4)
|
||||||
|
X(LWB4)
|
||||||
|
X(LWT5)
|
||||||
|
X(LWB5)
|
||||||
|
X(LWT6)
|
||||||
|
X(LWB6)
|
||||||
|
X(LWT7)
|
||||||
|
X(LWB7)
|
||||||
|
X(LWSPINETL0)
|
||||||
|
X(LWSPINETL1)
|
||||||
|
X(LWSPINETL2)
|
||||||
|
X(LWSPINETL3)
|
||||||
|
X(LWSPINETL4)
|
||||||
|
X(LWSPINETL5)
|
||||||
|
X(LWSPINETL6)
|
||||||
|
X(LWSPINETL7)
|
||||||
|
X(LWSPINETR0)
|
||||||
|
X(LWSPINETR1)
|
||||||
|
X(LWSPINETR2)
|
||||||
|
X(LWSPINETR3)
|
||||||
|
X(LWSPINETR4)
|
||||||
|
X(LWSPINETR5)
|
||||||
|
X(LWSPINETR6)
|
||||||
|
X(LWSPINETR7)
|
||||||
|
X(LWSPINEBL0)
|
||||||
|
X(LWSPINEBL1)
|
||||||
|
X(LWSPINEBL2)
|
||||||
|
X(LWSPINEBL3)
|
||||||
|
X(LWSPINEBL4)
|
||||||
|
X(LWSPINEBL5)
|
||||||
|
X(LWSPINEBL6)
|
||||||
|
X(LWSPINEBL7)
|
||||||
|
X(LWSPINEBR0)
|
||||||
|
X(LWSPINEBR1)
|
||||||
|
X(LWSPINEBR2)
|
||||||
|
X(LWSPINEBR3)
|
||||||
|
X(LWSPINEBR4)
|
||||||
|
X(LWSPINEBR5)
|
||||||
|
X(LWSPINEBR6)
|
||||||
|
X(LWSPINEBR7)
|
||||||
|
X(LWI0)
|
||||||
|
X(LWI1)
|
||||||
|
X(LWI2)
|
||||||
|
X(LWI3)
|
||||||
|
X(LWI4)
|
||||||
|
X(LWI5)
|
||||||
|
X(LWI6)
|
||||||
|
X(LWI7)
|
||||||
|
X(LWO0)
|
||||||
|
X(LWO1)
|
||||||
|
X(LWO2)
|
||||||
|
X(LWO3)
|
||||||
|
X(LWO4)
|
||||||
|
X(LWO5)
|
||||||
|
X(LWO6)
|
||||||
|
X(LWO7)
|
||||||
|
|
||||||
// IOLOGIC
|
// IOLOGIC
|
||||||
X(TX)
|
X(TX)
|
||||||
X(XXX_VSS)
|
X(XXX_VSS)
|
||||||
@ -826,6 +901,11 @@ X(CENT_SPINE_PCLK)
|
|||||||
X(SPINE_TAP_PCLK)
|
X(SPINE_TAP_PCLK)
|
||||||
X(TAP_BRANCH_PCLK)
|
X(TAP_BRANCH_PCLK)
|
||||||
X(BRANCH_PCLK)
|
X(BRANCH_PCLK)
|
||||||
|
X(CENT_SPINE_SCLK)
|
||||||
|
X(SPINE_TAP_SCLK_0)
|
||||||
|
X(SPINE_TAP_SCLK_1)
|
||||||
|
X(TAP_BRANCH_SCLK)
|
||||||
|
X(BRANCH_SCLK)
|
||||||
X(clksetpos)
|
X(clksetpos)
|
||||||
X(clkholdpos)
|
X(clkholdpos)
|
||||||
X(clk_qpos)
|
X(clk_qpos)
|
||||||
|
@ -1033,9 +1033,11 @@ static void pack_io(Context *ctx)
|
|||||||
if (constr_bel != ci->attrs.end()) {
|
if (constr_bel != ci->attrs.end()) {
|
||||||
constr_bel_name = constr_bel->second.as_string();
|
constr_bel_name = constr_bel->second.as_string();
|
||||||
}
|
}
|
||||||
constr_bel = iob->attrs.find(id_BEL);
|
if (iob != nullptr) {
|
||||||
if (constr_bel != iob->attrs.end()) {
|
constr_bel = iob->attrs.find(id_BEL);
|
||||||
constr_bel_name = constr_bel->second.as_string();
|
if (constr_bel != iob->attrs.end()) {
|
||||||
|
constr_bel_name = constr_bel->second.as_string();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (!constr_bel_name.empty()) {
|
if (!constr_bel_name.empty()) {
|
||||||
BelId constr_bel = ctx->getBelByNameStr(constr_bel_name);
|
BelId constr_bel = ctx->getBelByNameStr(constr_bel_name);
|
||||||
|
@ -95,7 +95,7 @@ bool Arch::isBelLocationValid(BelId bel) const
|
|||||||
}
|
}
|
||||||
return logic_cells_compatible(bel_cells.data(), num_cells);
|
return logic_cells_compatible(bel_cells.data(), num_cells);
|
||||||
} else {
|
} else {
|
||||||
CellInfo *cell = getBoundBelCell(bel);
|
const CellInfo *cell = getBoundBelCell(bel);
|
||||||
if (cell == nullptr)
|
if (cell == nullptr)
|
||||||
return true;
|
return true;
|
||||||
else if (cell->type == id_SB_IO) {
|
else if (cell->type == id_SB_IO) {
|
||||||
@ -107,7 +107,7 @@ bool Arch::isBelLocationValid(BelId bel) const
|
|||||||
for (auto pin : getWireBelPins(wire)) {
|
for (auto pin : getWireBelPins(wire)) {
|
||||||
if (pin.pin == id_PLLOUT_A || pin.pin == id_PLLOUT_B) {
|
if (pin.pin == id_PLLOUT_A || pin.pin == id_PLLOUT_B) {
|
||||||
// Is there a PLL there ?
|
// Is there a PLL there ?
|
||||||
auto pll_cell = getBoundBelCell(pin.bel);
|
const CellInfo *pll_cell = getBoundBelCell(pin.bel);
|
||||||
if (pll_cell == nullptr)
|
if (pll_cell == nullptr)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -116,11 +116,11 @@ bool Arch::isBelLocationValid(BelId bel) const
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
// Is that SB_IO used at an input ?
|
// Is that SB_IO used at an input ?
|
||||||
if ((cell->ports[id_D_IN_0].net == nullptr) && (cell->ports[id_D_IN_1].net == nullptr))
|
if ((cell->getPort(id_D_IN_0) == nullptr) && (cell->getPort(id_D_IN_1) == nullptr))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Are we perhaps a PAD INPUT Bel that can be placed here?
|
// Are we perhaps a PAD INPUT Bel that can be placed here?
|
||||||
if (pll_cell->attrs[id_BEL_PAD_INPUT] == getBelName(bel).str(getCtx()))
|
if (str_or_default(pll_cell->attrs, id_BEL_PAD_INPUT, "") == getBelName(bel).str(getCtx()))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Conflict
|
// Conflict
|
||||||
@ -144,7 +144,7 @@ bool Arch::isBelLocationValid(BelId bel) const
|
|||||||
} else {
|
} else {
|
||||||
// Check LVDS IO is not placed at complement location
|
// Check LVDS IO is not placed at complement location
|
||||||
BelId compBel = getBelByLocation(compLoc);
|
BelId compBel = getBelByLocation(compLoc);
|
||||||
CellInfo *compCell = getBoundBelCell(compBel);
|
const CellInfo *compCell = getBoundBelCell(compBel);
|
||||||
if (compCell && compCell->ioInfo.lvds)
|
if (compCell && compCell->ioInfo.lvds)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -161,10 +161,10 @@ bool Arch::isBelLocationValid(BelId bel) const
|
|||||||
_io_pintype_need_clk_en(cell->ioInfo.pintype),
|
_io_pintype_need_clk_en(cell->ioInfo.pintype),
|
||||||
_io_pintype_need_clk_en(compCell->ioInfo.pintype),
|
_io_pintype_need_clk_en(compCell->ioInfo.pintype),
|
||||||
};
|
};
|
||||||
NetInfo *nets[] = {
|
const NetInfo *nets[] = {
|
||||||
cell->ports[id_INPUT_CLK].net, compCell->ports[id_INPUT_CLK].net,
|
cell->getPort(id_INPUT_CLK), compCell->getPort(id_INPUT_CLK),
|
||||||
cell->ports[id_OUTPUT_CLK].net, compCell->ports[id_OUTPUT_CLK].net,
|
cell->getPort(id_OUTPUT_CLK), compCell->getPort(id_OUTPUT_CLK),
|
||||||
cell->ports[id_CLOCK_ENABLE].net, compCell->ports[id_CLOCK_ENABLE].net,
|
cell->getPort(id_CLOCK_ENABLE), compCell->getPort(id_CLOCK_ENABLE),
|
||||||
};
|
};
|
||||||
|
|
||||||
for (int i = 0; i < 6; i++)
|
for (int i = 0; i < 6; i++)
|
||||||
|
Loading…
Reference in New Issue
Block a user