From e9fe444dc7dd5bf09f50ef6c742a637f6bc24f41 Mon Sep 17 00:00:00 2001 From: David Shah Date: Wed, 7 Nov 2018 20:44:43 +0000 Subject: ecp5: Adding ancillary DCU bels Signed-off-by: David Shah --- ecp5/arch.cc | 2 +- ecp5/bitstream.cc | 17 +++++++++++++++++ ecp5/constids.inc | 7 +++++++ ecp5/pack.cc | 32 ++++++++++++++++++++++++++++++++ 4 files changed, 57 insertions(+), 1 deletion(-) 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 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; + } } } } -- cgit v1.2.3