ecp5: Helper functions and bitstream for DQS
Signed-off-by: David Shah <dave@ds0.me>
This commit is contained in:
parent
eb45956d0e
commit
4402361246
@ -1191,6 +1191,36 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex
|
||||
cc.tiles[tile].add_enum(clkdiv + ".DIV", str_or_default(ci->params, ctx->id("DIV"), "2.0"));
|
||||
cc.tiles[tile].add_enum(clkdiv + ".GSR", str_or_default(ci->params, ctx->id("GSR"), "DISABLED"));
|
||||
} else if (ci->type == id_TRELLIS_ECLKBUF) {
|
||||
} else if (ci->type == id_DQSBUFM) {
|
||||
Loc loc = ctx->getBelLocation(ci->bel);
|
||||
bool l = loc.y < 10;
|
||||
std::string pic = l ? "PICL" : "PICR";
|
||||
TileGroup tg;
|
||||
tg.tiles.push_back(ctx->getTileByTypeAndLocation(loc.y - 2, loc.x, pic + "1_DQS0"));
|
||||
tg.tiles.push_back(ctx->getTileByTypeAndLocation(loc.y - 1, loc.x, pic + "2_DQS1"));
|
||||
tg.tiles.push_back(ctx->getTileByTypeAndLocation(loc.y, loc.x, pic + "0_DQS2"));
|
||||
tg.tiles.push_back(ctx->getTileByTypeAndLocation(loc.y + 1, loc.x, pic + "1_DQS3"));
|
||||
tg.config.add_enum("DQS.MODE", "DQSBUFM");
|
||||
tg.config.add_enum("DQS.DQS_LI_DEL_ADJ", str_or_default(ci->params, ctx->id("DQS_LI_DEL_ADJ"), "PLUS"));
|
||||
tg.config.add_enum("DQS.DQS_LO_DEL_ADJ", str_or_default(ci->params, ctx->id("DQS_LO_DEL_ADJ"), "PLUS"));
|
||||
int li_del_value = int_or_default(ci->params, ctx->id("DQS_LI_DEL_VAL"), 0);
|
||||
if (str_or_default(ci->params, ctx->id("DQS_LI_DEL_ADJ"), "PLUS") == "MINUS")
|
||||
li_del_value = (256 - li_del_value) & 0xFF;
|
||||
int lo_del_value = int_or_default(ci->params, ctx->id("DQS_LO_DEL_VAL"), 0);
|
||||
if (str_or_default(ci->params, ctx->id("DQS_LO_DEL_ADJ"), "PLUS") == "MINUS")
|
||||
lo_del_value = (256 - lo_del_value) & 0xFF;
|
||||
tg.config.add_word("DQS.DQS_LI_DEL_VAL", int_to_bitvector(li_del_value, 8));
|
||||
tg.config.add_word("DQS.DQS_LO_DEL_VAL", int_to_bitvector(lo_del_value, 8));
|
||||
tg.config.add_enum("DQS.WRLOADN_USED", get_net_or_empty(ci, id_WRLOADN) != nullptr ? "YES" : "NO");
|
||||
tg.config.add_enum("DQS.RDLOADN_USED", get_net_or_empty(ci, id_RDLOADN) != nullptr ? "YES" : "NO");
|
||||
tg.config.add_enum("DQS.PAUSE_USED", get_net_or_empty(ci, id_PAUSE) != nullptr ? "YES" : "NO");
|
||||
tg.config.add_enum("DQS.READ_USED",
|
||||
(get_net_or_empty(ci, id_READ0) != nullptr || get_net_or_empty(ci, id_READ1) != nullptr)
|
||||
? "YES"
|
||||
: "NO");
|
||||
tg.config.add_enum("DQS.DDRDEL", get_net_or_empty(ci, id_DDRDEL) != nullptr ? "DDRDEL" : "0");
|
||||
tg.config.add_enum("DQS.GSR", str_or_default(ci->params, ctx->id("GSR"), "DISABLED"));
|
||||
cc.tilegroups.push_back(tg);
|
||||
} else {
|
||||
NPNR_ASSERT_FALSE("unsupported cell type");
|
||||
}
|
||||
|
33
ecp5/pack.cc
33
ecp5/pack.cc
@ -1673,6 +1673,39 @@ class Ecp5Packer
|
||||
return iol_ptr;
|
||||
};
|
||||
|
||||
auto process_dqs_port = [&](CellInfo *prim, CellInfo *pio, CellInfo *iol, IdString port) {
|
||||
NetInfo *sig = nullptr;
|
||||
if (prim->ports.count(port))
|
||||
sig = prim->ports[port].net;
|
||||
if (sig == nullptr || sig->driver.cell == nullptr)
|
||||
log_error("Port %s of cell '%s' cannot be disconnected, it must be driven by a DQSBUFM\n",
|
||||
port.c_str(ctx), prim->name.c_str(ctx));
|
||||
if (iol->ports.at(port).net != nullptr) {
|
||||
if (iol->ports.at(port).net != sig) {
|
||||
log_error("IOLOGIC '%s' has conflicting %s signals '%s' and '%s'\n", iol->name.c_str(ctx),
|
||||
port.c_str(ctx), iol->ports[port].net->name.c_str(ctx), sig->name.c_str(ctx));
|
||||
}
|
||||
} else {
|
||||
bool dqsr;
|
||||
int dqsgroup;
|
||||
bool has_dqs = ctx->getPIODQSGroup(get_pio_bel(pio, prim), dqsr, dqsgroup);
|
||||
if (!has_dqs)
|
||||
log_error("Primitive '%s' cannot be connected to top level port '%s' as the associated pin is not "
|
||||
"in any DQS group",
|
||||
prim->name.c_str(ctx), pio->name.c_str(ctx));
|
||||
if (sig->driver.cell->type != id_DQSBUFM || sig->driver.port != port)
|
||||
log_error("Port %s of cell '%s' must be driven by port %s of a DQSBUFM", port.c_str(ctx),
|
||||
prim->name.c_str(ctx), port.c_str(ctx));
|
||||
auto &driver_group = dqsbuf_dqsg.at(sig->driver.cell->name);
|
||||
if (driver_group.first != dqsr || driver_group.second != dqsgroup)
|
||||
log_error("DQS group mismatch, port %s of '%s' in group %cDQ%d is driven by DQSBUFM '%s' in group "
|
||||
"%cDQ%d\n",
|
||||
port.c_str(ctx), prim->name.c_str(ctx), dqsr ? 'R' : 'L', dqsgroup,
|
||||
sig->driver.cell->name.c_str(ctx), driver_group.first ? 'R' : 'L', driver_group.second);
|
||||
replace_port(prim, port, iol, port);
|
||||
}
|
||||
};
|
||||
|
||||
for (auto cell : sorted(ctx->cells)) {
|
||||
CellInfo *ci = cell.second;
|
||||
if (ci->type == ctx->id("IDDRX1F")) {
|
||||
|
Loading…
Reference in New Issue
Block a user