aboutsummaryrefslogtreecommitdiffstats
path: root/ecp5
diff options
context:
space:
mode:
authorDavid Shah <dave@ds0.me>2018-11-07 20:44:43 +0000
committerDavid Shah <dave@ds0.me>2018-11-15 11:30:27 +0000
commite9fe444dc7dd5bf09f50ef6c742a637f6bc24f41 (patch)
tree104c1cafa0df1f91b90ab039bbb79cddacb5824e /ecp5
parent37cbabecfbd22119ad5ba0adfc4d7011831a9af4 (diff)
downloadnextpnr-e9fe444dc7dd5bf09f50ef6c742a637f6bc24f41.tar.gz
nextpnr-e9fe444dc7dd5bf09f50ef6c742a637f6bc24f41.tar.bz2
nextpnr-e9fe444dc7dd5bf09f50ef6c742a637f6bc24f41.zip
ecp5: Adding ancillary DCU bels
Signed-off-by: David Shah <dave@ds0.me>
Diffstat (limited to 'ecp5')
-rw-r--r--ecp5/arch.cc2
-rw-r--r--ecp5/bitstream.cc17
-rw-r--r--ecp5/constids.inc7
-rw-r--r--ecp5/pack.cc32
4 files changed, 57 insertions, 1 deletions
diff --git a/ecp5/arch.cc b/ecp5/arch.cc
index 93ed5788..a0d8e8ae 100644
--- a/ecp5/arch.cc
+++ b/ecp5/arch.cc
@@ -651,7 +651,7 @@ TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, in
return TMG_IGNORE; // FIXME
} else if (cell->type == id_EHXPLLL) {
return TMG_IGNORE;
- } else if (cell->type == id_DCUA) {
+ } else if (cell->type == id_DCUA || cell->type == id_EXTREFB || cell->type == id_PCSCLKDIV) {
return TMG_IGNORE; // FIXME
} else {
NPNR_ASSERT_FALSE_STR("no timing data for cell type '" + cell->type.str(this) + "'");
diff --git a/ecp5/bitstream.cc b/ecp5/bitstream.cc
index 00486e39..2df0ed0b 100644
--- a/ecp5/bitstream.cc
+++ b/ecp5/bitstream.cc
@@ -514,6 +514,12 @@ static std::vector<bool> parse_config_str(std::string str, int length)
for (int i = 0; i < length; i++)
if (value & (1 << i))
word.at(i) = true;
+ } else {
+ NPNR_ASSERT(length < 64);
+ unsigned long long value = std::stoull(str);
+ for (int i = 0; i < length; i++)
+ if (value & (1 << i))
+ word.at(i) = true;
}
return word;
}
@@ -1078,6 +1084,17 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex
#include "dcu_bitstream.h"
cc.tilegroups.push_back(tg);
tieoff_dcu_ports(ctx, cc, ci);
+ } else if (ci->type == id_EXTREFB) {
+ TileGroup tg;
+ tg.tiles = get_dcu_tiles(ctx, ci->bel);
+ tg.config.add_word("EXTREF.REFCK_DCBIAS_EN", parse_config_str(str_or_default(ci->params, ctx->id("REFCK_DCBIAS_EN"), "0"), 1));
+ tg.config.add_word("EXTREF.REFCK_RTERM", parse_config_str(str_or_default(ci->params, ctx->id("REFCK_RTERM"), "0"), 1));
+ tg.config.add_word("EXTREF.REFCK_PWDNB", parse_config_str(str_or_default(ci->params, ctx->id("REFCK_PWDNB"), "0"), 1));
+ cc.tilegroups.push_back(tg);
+ } else if (ci->type == id_PCSCLKDIV) {
+ Loc loc = ctx->getBelLocation(ci->bel);
+ std::string tname = ctx->getTileByTypeAndLocation(loc.y+1, loc.x, "BMID_0H");
+ cc.tiles[tname].add_enum("PCSCLKDIV" + std::to_string(loc.z), str_or_default(ci->params, ctx->id("GSR"), "ENABLED"));
} else {
NPNR_ASSERT_FALSE("unsupported cell type");
}
diff --git a/ecp5/constids.inc b/ecp5/constids.inc
index 4f5c3ef3..11ecc240 100644
--- a/ecp5/constids.inc
+++ b/ecp5/constids.inc
@@ -1110,3 +1110,10 @@ X(D_COUT18)
X(D_COUT19)
X(D_REFCLKI)
X(D_FFS_PLOL)
+
+X(PCSCLKDIV)
+X(SEL2)
+X(SEL1)
+X(SEL0)
+X(CDIV1)
+X(CDIVX) \ No newline at end of file
diff --git a/ecp5/pack.cc b/ecp5/pack.cc
index ae416a7b..66428e95 100644
--- a/ecp5/pack.cc
+++ b/ecp5/pack.cc
@@ -1039,6 +1039,8 @@ class Ecp5Packer
for (auto cell : sorted(ctx->cells)) {
CellInfo *ci = cell.second;
if (ci->type == id_DCUA) {
+ if (!ci->attrs.count(ctx->id("BEL")))
+ log_error("DCU must be constrained to a Bel!\n");
// Empty port auto-creation to generate correct tie-downs
BelId exemplar_bel;
for (auto bel : ctx->getBels()) {
@@ -1051,6 +1053,36 @@ class Ecp5Packer
for (auto pin : ctx->getBelPins(exemplar_bel))
if (ctx->getBelPinType(exemplar_bel, pin) == PORT_IN)
autocreate_empty_port(ci, pin);
+ } else if (ci->type == id_EXTREFB) {
+ const NetInfo *refo = net_or_nullptr(ci, id_REFCLKO);
+ CellInfo *dcu = nullptr;
+ if (refo == nullptr)
+ log_error("EXTREFB REFCLKO must not be unconnected\n");
+ for (auto user : refo->users) {
+ if (user.cell->type != id_DCUA || (dcu != nullptr && dcu != user.cell))
+ log_error("EXTREFB REFCLKO must only drive a single DCUA\n");
+ dcu = user.cell;
+ }
+ if (!dcu->attrs.count(ctx->id("BEL")))
+ log_error("DCU must be constrained to a Bel!\n");
+ std::string bel = dcu->attrs.at(ctx->id("BEL"));
+ NPNR_ASSERT(bel.substr(bel.length() - 3) == "DCU");
+ bel.replace(bel.length() - 3, 3, "EXTREF");
+ ci->attrs[ctx->id("BEL")] = bel;
+ } else if (ci->type == id_PCSCLKDIV) {
+ const NetInfo *clki = net_or_nullptr(ci, id_CLKI);
+ if (clki != nullptr && clki->driver.cell != nullptr && clki->driver.cell->type == id_DCUA) {
+ CellInfo *dcu = clki->driver.cell;
+ if (!dcu->attrs.count(ctx->id("BEL")))
+ log_error("DCU must be constrained to a Bel!\n");
+ BelId bel = ctx->getBelByName(ctx->id(dcu->attrs.at(ctx->id("BEL"))));
+ if (bel == BelId())
+ log_error("Invalid DCU bel '%s'\n", dcu->attrs.at(ctx->id("BEL")).c_str());
+ Loc loc = ctx->getBelLocation(bel);
+ // DCU0 -> CLKDIV z=0; DCU1 -> CLKDIV z=1
+ ci->constr_abs_z = true;
+ ci->constr_z = (loc.x >= 69) ? 1 : 0;
+ }
}
}
}