ecp5: Adding ancillary DCU bels

Signed-off-by: David Shah <dave@ds0.me>
This commit is contained in:
David Shah 2018-11-07 20:44:43 +00:00
parent 37cbabecfb
commit e9fe444dc7
4 changed files with 57 additions and 1 deletions

View File

@ -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) + "'");

View File

@ -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");
}

View File

@ -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)

View File

@ -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;
}
}
}
}