aboutsummaryrefslogtreecommitdiffstats
path: root/gowin
diff options
context:
space:
mode:
authorPepijn de Vos <pepijndevos@gmail.com>2022-07-02 13:29:44 +0200
committerPepijn de Vos <pepijndevos@gmail.com>2022-07-02 13:29:44 +0200
commit0641ff47d9c437c02d77363d568b106c4ceae155 (patch)
tree0c2fb9f751004c7dcad0c7c618d3d6dd6b2cf0e3 /gowin
parentb7992ec7724000f813ab053ac6042326f3795471 (diff)
parentb4337d99fde46abe85cab8bdf98a681eefe1f3e1 (diff)
downloadnextpnr-0641ff47d9c437c02d77363d568b106c4ceae155.tar.gz
nextpnr-0641ff47d9c437c02d77363d568b106c4ceae155.tar.bz2
nextpnr-0641ff47d9c437c02d77363d568b106c4ceae155.zip
Merge branch 'master' into shadowram
Diffstat (limited to 'gowin')
-rw-r--r--gowin/arch.cc224
-rw-r--r--gowin/arch.h10
-rw-r--r--gowin/cells.cc3
-rw-r--r--gowin/constids.inc80
-rw-r--r--gowin/pack.cc8
5 files changed, 310 insertions, 15 deletions
diff --git a/gowin/arch.cc b/gowin/arch.cc
index 65f15204..db1430f9 100644
--- a/gowin/arch.cc
+++ b/gowin/arch.cc
@@ -19,6 +19,7 @@
*/
#include <boost/algorithm/string.hpp>
+#include <cells.h>
#include <iostream>
#include <math.h>
#include <regex>
@@ -33,6 +34,8 @@
NEXTPNR_NAMESPACE_BEGIN
+const PairPOD *pairLookup(const PairPOD *list, const size_t len, const int dest);
+
// GUI
void Arch::fixClockSpineDecals(void)
{
@@ -175,6 +178,145 @@ DecalXY Arch::getWireDecal(WireId wire) const
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)
{
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);
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);
}
@@ -628,6 +778,28 @@ DelayQuad Arch::getWireTypeDelay(IdString wire)
case ID_W830:
len = id_X8;
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_GT10:
glbsrc = id_SPINE_TAP_PCLK;
@@ -647,7 +819,9 @@ DelayQuad Arch::getWireTypeDelay(IdString wire)
glbsrc = id_BRANCH_PCLK;
break;
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);
} else if (wire.str(this).rfind("UNK", 0) == 0) {
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 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 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::string line, pinline;
enum
@@ -732,15 +906,23 @@ void Arch::read_cst(std::istream &in)
continue;
}
switch (cst_type) {
- case clock: { // CLOCK name BUFG|S
+ case clock: { // CLOCK name BUFG|S=#
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') {
auto ni = nets.find(net);
if (ni == nets.end()) {
log_info("Net %s not found\n", net.c_str(this));
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 {
log_info("BUFG isn't supported\n");
continue;
@@ -1021,6 +1203,31 @@ Arch::Arch(ArchArgs args) : args(args)
bool dff = true;
bool oddrc = false;
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:
snprintf(buf, 32, "R%dC%d_GSR0", row + 1, col + 1);
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));
IdString pipname = id(buf);
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
srcid = IdString(pip.src_id);
GlobalAliasPOD alias;
@@ -1705,6 +1906,7 @@ bool Arch::route()
}
getCtx()->settings[id_route] = 1;
archInfoToAttributes();
+ fix_longwire_bels();
return result;
}
diff --git a/gowin/arch.h b/gowin/arch.h
index c13cdf09..cd20f28a 100644
--- a/gowin/arch.h
+++ b/gowin/arch.h
@@ -459,6 +459,9 @@ struct Arch : BaseArch<ArchRanges>
void assignArchInfo() override;
bool cellsCompatible(const CellInfo **cells, int count) const;
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
unsigned int const chipdb_version = 1;
@@ -475,6 +478,9 @@ struct Arch : BaseArch<ArchRanges>
// XXX GW1NR-9 iobuf quirk
bool gw1n9_quirk = false;
+ // 8 Long wires
+ uint8_t avail_longwires = 0xff;
+
// Permissible combinations of modes in a single slice
std::map<const IdString, IdString> dff_comp_mode;
};
@@ -488,7 +494,9 @@ enum
lutram_0_z = 30, // start Z for the IOLOGIC bels
vcc_0_z = 277, // virtual VCC 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.
};
}
diff --git a/gowin/cells.cc b/gowin/cells.cc
index 0dc0ce06..d83b07c8 100644
--- a/gowin/cells.cc
+++ b/gowin/cells.cc
@@ -77,6 +77,9 @@ std::unique_ptr<CellInfo> create_generic_cell(Context *ctx, IdString type, std::
new_cell->addOutput(id_G);
} else if (type == id_VCC) {
new_cell->addOutput(id_V);
+ } else if (type == id_BUFS) {
+ new_cell->addInput(id_I);
+ new_cell->addOutput(id_O);
} else {
log_error("unable to create generic cell of type %s\n", type.c_str(ctx));
}
diff --git a/gowin/constids.inc b/gowin/constids.inc
index 0c788ecd..8916f093 100644
--- a/gowin/constids.inc
+++ b/gowin/constids.inc
@@ -679,6 +679,81 @@ X(IOBHS)
X(IOBIS)
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
X(TX)
X(XXX_VSS)
@@ -826,6 +901,11 @@ X(CENT_SPINE_PCLK)
X(SPINE_TAP_PCLK)
X(TAP_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(clkholdpos)
X(clk_qpos)
diff --git a/gowin/pack.cc b/gowin/pack.cc
index 0ba71705..fbd2092f 100644
--- a/gowin/pack.cc
+++ b/gowin/pack.cc
@@ -1033,9 +1033,11 @@ static void pack_io(Context *ctx)
if (constr_bel != ci->attrs.end()) {
constr_bel_name = constr_bel->second.as_string();
}
- constr_bel = iob->attrs.find(id_BEL);
- if (constr_bel != iob->attrs.end()) {
- constr_bel_name = constr_bel->second.as_string();
+ if (iob != nullptr) {
+ constr_bel = iob->attrs.find(id_BEL);
+ if (constr_bel != iob->attrs.end()) {
+ constr_bel_name = constr_bel->second.as_string();
+ }
}
if (!constr_bel_name.empty()) {
BelId constr_bel = ctx->getBelByNameStr(constr_bel_name);