ecp5: Add support for IO registers
Signed-off-by: David Shah <dave@ds0.me>
This commit is contained in:
parent
a14555c8d1
commit
c6401413a4
@ -119,7 +119,16 @@ inline const NetInfo *get_net_or_empty(const CellInfo *cell, const IdString port
|
|||||||
return found->second.net;
|
return found->second.net;
|
||||||
else
|
else
|
||||||
return nullptr;
|
return nullptr;
|
||||||
};
|
}
|
||||||
|
|
||||||
|
inline NetInfo *get_net_or_empty(CellInfo *cell, const IdString port)
|
||||||
|
{
|
||||||
|
auto found = cell->ports.find(port);
|
||||||
|
if (found != cell->ports.end())
|
||||||
|
return found->second.net;
|
||||||
|
else
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_END
|
NEXTPNR_NAMESPACE_END
|
||||||
|
|
||||||
|
@ -888,9 +888,15 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex
|
|||||||
std::string datamux_oddr = str_or_default(ci->params, ctx->id("DATAMUX_ODDR"), "PADDO");
|
std::string datamux_oddr = str_or_default(ci->params, ctx->id("DATAMUX_ODDR"), "PADDO");
|
||||||
if (datamux_oddr != "PADDO")
|
if (datamux_oddr != "PADDO")
|
||||||
cc.tiles[pic_tile].add_enum(pio + ".DATAMUX_ODDR", datamux_oddr);
|
cc.tiles[pic_tile].add_enum(pio + ".DATAMUX_ODDR", datamux_oddr);
|
||||||
|
std::string datamux_oreg = str_or_default(ci->params, ctx->id("DATAMUX_OREG"), "PADDO");
|
||||||
|
if (datamux_oreg != "PADDO")
|
||||||
|
cc.tiles[pic_tile].add_enum(pio + ".DATAMUX_OREG", datamux_oreg);
|
||||||
std::string datamux_mddr = str_or_default(ci->params, ctx->id("DATAMUX_MDDR"), "PADDO");
|
std::string datamux_mddr = str_or_default(ci->params, ctx->id("DATAMUX_MDDR"), "PADDO");
|
||||||
if (datamux_mddr != "PADDO")
|
if (datamux_mddr != "PADDO")
|
||||||
cc.tiles[pic_tile].add_enum(pio + ".DATAMUX_MDDR", datamux_mddr);
|
cc.tiles[pic_tile].add_enum(pio + ".DATAMUX_MDDR", datamux_mddr);
|
||||||
|
std::string trimux_tsreg = str_or_default(ci->params, ctx->id("TRIMUX_TSREG"), "PADDT");
|
||||||
|
if (trimux_tsreg != "PADDT")
|
||||||
|
cc.tiles[pic_tile].add_enum(pio + ".TRIMUX_TSREG", trimux_tsreg);
|
||||||
} else if (ci->type == ctx->id("DCCA")) {
|
} else if (ci->type == ctx->id("DCCA")) {
|
||||||
const NetInfo *cen = get_net_or_empty(ci, ctx->id("CE"));
|
const NetInfo *cen = get_net_or_empty(ci, ctx->id("CE"));
|
||||||
if (cen != nullptr) {
|
if (cen != nullptr) {
|
||||||
|
97
ecp5/pack.cc
97
ecp5/pack.cc
@ -1844,6 +1844,8 @@ class Ecp5Packer
|
|||||||
|
|
||||||
auto set_iologic_mode = [&](CellInfo *iol, std::string mode) {
|
auto set_iologic_mode = [&](CellInfo *iol, std::string mode) {
|
||||||
auto &curr_mode = iol->params[ctx->id("MODE")].str;
|
auto &curr_mode = iol->params[ctx->id("MODE")].str;
|
||||||
|
if (curr_mode != "NONE" && mode == "IREG_OREG")
|
||||||
|
return;
|
||||||
if (curr_mode != "NONE" && curr_mode != "IREG_OREG" && curr_mode != mode)
|
if (curr_mode != "NONE" && curr_mode != "IREG_OREG" && curr_mode != mode)
|
||||||
log_error("IOLOGIC '%s' has conflicting modes '%s' and '%s'\n", iol->name.c_str(ctx), curr_mode.c_str(),
|
log_error("IOLOGIC '%s' has conflicting modes '%s' and '%s'\n", iol->name.c_str(ctx), curr_mode.c_str(),
|
||||||
mode.c_str());
|
mode.c_str());
|
||||||
@ -2240,6 +2242,101 @@ class Ecp5Packer
|
|||||||
std::string(ci->type == ctx->id("TSHX2DQSA") ? "DQSW" : "DQSW270");
|
std::string(ci->type == ctx->id("TSHX2DQSA") ? "DQSW" : "DQSW270");
|
||||||
iol->params[ctx->id("IOLTOMUX")] = std::string("TDDR");
|
iol->params[ctx->id("IOLTOMUX")] = std::string("TDDR");
|
||||||
packed_cells.insert(cell.first);
|
packed_cells.insert(cell.first);
|
||||||
|
} else if (ci->type == ctx->id("TRELLIS_FF") && bool_or_default(ci->attrs, ctx->id("syn_useioff"))) {
|
||||||
|
// Pack IO flipflop into IOLOGIC
|
||||||
|
std::string mode = str_or_default(ci->attrs, ctx->id("ioff_dir"), "");
|
||||||
|
if (mode != "output") {
|
||||||
|
// See if it can be packed as an input ff
|
||||||
|
NetInfo *d = get_net_or_empty(ci, ctx->id("DI"));
|
||||||
|
CellInfo *pio = net_driven_by(ctx, d, is_trellis_io, id_O);
|
||||||
|
if (pio != nullptr && d->users.size() == 1) {
|
||||||
|
// Input FF
|
||||||
|
CellInfo *iol;
|
||||||
|
if (pio_iologic.count(pio->name))
|
||||||
|
iol = pio_iologic.at(pio->name);
|
||||||
|
else
|
||||||
|
iol = create_pio_iologic(pio, ci);
|
||||||
|
set_iologic_mode(iol, "IREG_OREG");
|
||||||
|
set_iologic_sclk(iol, ci, ctx->id("CLK"), true);
|
||||||
|
set_iologic_lsr(iol, ci, ctx->id("LSR"), true);
|
||||||
|
// Handle CLK and CE muxes
|
||||||
|
if (str_or_default(ci->params, ctx->id("CLKMUX")) == "INV")
|
||||||
|
iol->params[ctx->id("CLKIMUX")] = std::string("INV");
|
||||||
|
if (str_or_default(ci->params, ctx->id("CEMUX"), "CE") == "CE") {
|
||||||
|
iol->params[ctx->id("CEIMUX")] = std::string("CEMUX");
|
||||||
|
iol->params[ctx->id("CEMUX")] = std::string("CE");
|
||||||
|
replace_port(ci, ctx->id("CE"), iol, ctx->id("CE"));
|
||||||
|
} else {
|
||||||
|
iol->params[ctx->id("CEIMUX")] = std::string("1");
|
||||||
|
}
|
||||||
|
// Set IOLOGIC params from FF params
|
||||||
|
iol->params[ctx->id("FF.INREGMODE")] = std::string("FF");
|
||||||
|
iol->params[ctx->id("FF.REGSET")] = str_or_default(ci->params, ctx->id("REGSET"), "RESET");
|
||||||
|
iol->params[ctx->id("SRMODE")] = str_or_default(ci->params, ctx->id("SRMODE"), "ASYNC");
|
||||||
|
iol->params[ctx->id("GSR")] = str_or_default(ci->params, ctx->id("GSR"), "DISABLED");
|
||||||
|
replace_port(ci, ctx->id("DI"), iol, id_PADDI);
|
||||||
|
replace_port(ci, ctx->id("Q"), iol, id_INFF);
|
||||||
|
packed_cells.insert(cell.first);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mode != "input") {
|
||||||
|
CellInfo *pio_t = net_only_drives(ctx, ci->ports.at(ctx->id("Q")).net, is_trellis_io, id_T, true);
|
||||||
|
CellInfo *pio_i = net_only_drives(ctx, ci->ports.at(ctx->id("Q")).net, is_trellis_io, id_I, true);
|
||||||
|
if (pio_t != nullptr || pio_i != nullptr) {
|
||||||
|
// Output or tristate FF
|
||||||
|
bool tri = (pio_t != nullptr);
|
||||||
|
CellInfo *pio = tri ? pio_t : pio_i;
|
||||||
|
CellInfo *iol;
|
||||||
|
if (pio_iologic.count(pio->name))
|
||||||
|
iol = pio_iologic.at(pio->name);
|
||||||
|
else
|
||||||
|
iol = create_pio_iologic(pio, ci);
|
||||||
|
set_iologic_mode(iol, "IREG_OREG");
|
||||||
|
// Connection between FF and PIO
|
||||||
|
replace_port(ci, ctx->id("Q"), iol, tri ? id_IOLTO : id_IOLDO);
|
||||||
|
if (tri) {
|
||||||
|
if (!pio->ports.count(id_IOLTO)) {
|
||||||
|
pio->ports[id_IOLTO].name = id_IOLTO;
|
||||||
|
pio->ports[id_IOLTO].type = PORT_IN;
|
||||||
|
}
|
||||||
|
pio->params[ctx->id("TRIMUX_TSREG")] = std::string("IOLTO");
|
||||||
|
replace_port(pio, id_I, pio, id_IOLTO);
|
||||||
|
} else {
|
||||||
|
if (!pio->ports.count(id_IOLDO)) {
|
||||||
|
pio->ports[id_IOLDO].name = id_IOLDO;
|
||||||
|
pio->ports[id_IOLDO].type = PORT_IN;
|
||||||
|
}
|
||||||
|
pio->params[ctx->id("DATAMUX_OREG")] = std::string("IOLDO");
|
||||||
|
replace_port(pio, id_I, pio, id_IOLDO);
|
||||||
|
}
|
||||||
|
|
||||||
|
set_iologic_sclk(iol, ci, ctx->id("CLK"), false);
|
||||||
|
set_iologic_lsr(iol, ci, ctx->id("LSR"), false);
|
||||||
|
|
||||||
|
// Handle CLK and CE muxes
|
||||||
|
if (str_or_default(ci->params, ctx->id("CLKMUX")) == "INV")
|
||||||
|
iol->params[ctx->id("CLKOMUX")] = std::string("INV");
|
||||||
|
if (str_or_default(ci->params, ctx->id("CEMUX"), "CE") == "CE") {
|
||||||
|
iol->params[ctx->id("CEOMUX")] = std::string("CEMUX");
|
||||||
|
iol->params[ctx->id("CEMUX")] = std::string("CE");
|
||||||
|
replace_port(ci, ctx->id("CE"), iol, ctx->id("CE"));
|
||||||
|
} else {
|
||||||
|
iol->params[ctx->id("CEOMUX")] = std::string("1");
|
||||||
|
}
|
||||||
|
// FF params
|
||||||
|
iol->params[ctx->id(tri ? "TSREG.OUTREGMODE" : "OUTREG.OUTREGMODE")] = std::string("FF");
|
||||||
|
iol->params[ctx->id(tri ? "TSREG.REGSET" : "OUTREG.REGSET")] =
|
||||||
|
str_or_default(ci->params, ctx->id("REGSET"), "RESET");
|
||||||
|
iol->params[ctx->id("SRMODE")] = str_or_default(ci->params, ctx->id("SRMODE"), "ASYNC");
|
||||||
|
// Data input
|
||||||
|
replace_port(ci, ctx->id("DI"), iol, tri ? id_TSDATA0 : id_TXDATA0);
|
||||||
|
iol->params[ctx->id("GSR")] = str_or_default(ci->params, ctx->id("GSR"), "DISABLED");
|
||||||
|
packed_cells.insert(cell.first);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log_error("Failed to pack flipflop '%s' with 'syn_useioff' set into IOLOGIC.\n", ci->name.c_str(ctx));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
flush_cells();
|
flush_cells();
|
||||||
|
Loading…
Reference in New Issue
Block a user