nexus: Basic packer and FASM support for I/ODDR

Signed-off-by: gatecat <gatecat@ds0.me>
This commit is contained in:
gatecat 2021-07-28 13:18:38 +01:00
parent d0acb1b239
commit 5686fdcf1c
4 changed files with 124 additions and 2 deletions

View File

@ -514,3 +514,17 @@ X(SCLKIN)
X(SCLKOUT) X(SCLKOUT)
X(ECLK) X(ECLK)
X(CEIN) X(CEIN)
X(IDDRX1)
X(ODDRX1)
X(TXDATA0)
X(TXDATA1)
X(TSDATA0)
X(RXDATA0)
X(RXDATA1)
X(INDD)
X(DOUT)
X(TOUT)
X(Q0)
X(Q1)
X(SCLK)

View File

@ -257,11 +257,11 @@ struct NexusFasmWriter
if (pin_style & PINOPT_INV) { if (pin_style & PINOPT_INV) {
if (pin_mux == PINMUX_INV || pin_mux == PINMUX_0) if (pin_mux == PINMUX_INV || pin_mux == PINMUX_0)
write_bit(stringf("%sMUX.INV", ctx->nameOf(port.first))); write_bit(stringf("%sMUX.INV", ctx->nameOf(port.first)));
else if (pin_mux == PINMUX_SIG) else if (pin_mux == PINMUX_SIG && !(pin_style & PINBIT_GATED))
write_bit(stringf("%sMUX.%s", ctx->nameOf(port.first), ctx->nameOf(port.first))); write_bit(stringf("%sMUX.%s", ctx->nameOf(port.first), ctx->nameOf(port.first)));
} }
// Pins that must be explictly enabled // Pins that must be explictly enabled
if ((pin_style & PINBIT_GATED) && (pin_mux == PINMUX_SIG)) if ((pin_style & PINBIT_GATED) && (pin_mux == PINMUX_SIG) && (port.second.net != nullptr))
write_bit(stringf("%sMUX.%s", ctx->nameOf(port.first), ctx->nameOf(port.first))); write_bit(stringf("%sMUX.%s", ctx->nameOf(port.first), ctx->nameOf(port.first)));
// Pins that must be explictly set to 1 rather than just left floating // Pins that must be explictly set to 1 rather than just left floating
if ((pin_style & PINBIT_1) && (pin_mux == PINMUX_1)) if ((pin_style & PINBIT_1) && (pin_mux == PINMUX_1))
@ -560,6 +560,18 @@ struct NexusFasmWriter
return (key.size() >= 3 && (key.compare(key.size() - 3, 3, "MUX") == 0)); return (key.size() >= 3 && (key.compare(key.size() - 3, 3, "MUX") == 0));
} }
// Write config for some kind of IOLOGIC cell
void write_iol(const CellInfo *cell)
{
BelId bel = cell->bel;
push_bel(bel);
write_enum(cell, "MODE");
write_enum(cell, "IDDRX1_ODDRX1.OUTPUT");
write_enum(cell, "GSR", "DISABLED");
write_cell_muxes(cell);
pop();
}
// Write config for some kind of DSP cell // Write config for some kind of DSP cell
void write_dsp(const CellInfo *cell) void write_dsp(const CellInfo *cell)
{ {
@ -872,6 +884,8 @@ struct NexusFasmWriter
write_lram(ci); write_lram(ci);
else if (ci->type == id_DPHY_CORE) else if (ci->type == id_DPHY_CORE)
write_dphy(ci); write_dphy(ci);
else if (ci->type == id_IOLOGIC || ci->type == id_SIOLOGIC)
write_iol(ci);
blank(); blank();
} }
// Handle DCC route-throughs // Handle DCC route-throughs

View File

@ -1147,6 +1147,92 @@ struct NexusPacker
} }
} }
void transform_iologic()
{
dict<IdString, XFormRule> iol_rules;
iol_rules[id_IDDRX1].new_type = id_IOLOGIC;
iol_rules[id_IDDRX1].set_params.emplace_back(id_MODE, std::string("IDDRX1_ODDRX1"));
iol_rules[id_IDDRX1].port_xform[id_SCLK] = id_SCLKIN;
iol_rules[id_IDDRX1].port_xform[id_RST] = id_LSRIN;
iol_rules[id_IDDRX1].port_xform[id_D] = id_DI;
iol_rules[id_IDDRX1].port_xform[id_Q0] = id_RXDATA0;
iol_rules[id_IDDRX1].port_xform[id_Q1] = id_RXDATA1;
iol_rules[id_ODDRX1].new_type = id_IOLOGIC;
iol_rules[id_ODDRX1].set_params.emplace_back(id_MODE, std::string("IDDRX1_ODDRX1"));
iol_rules[id_ODDRX1].set_params.emplace_back(ctx->id("IDDRX1_ODDRX1.OUTPUT"), std::string("ENABLED"));
iol_rules[id_ODDRX1].port_xform[id_SCLK] = id_SCLKOUT;
iol_rules[id_ODDRX1].port_xform[id_RST] = id_LSROUT;
iol_rules[id_ODDRX1].port_xform[id_Q] = id_DOUT;
iol_rules[id_ODDRX1].port_xform[id_D0] = id_TXDATA0;
iol_rules[id_ODDRX1].port_xform[id_D1] = id_TXDATA1;
generic_xform(iol_rules, true);
}
void merge_iol_cell(CellInfo *base, CellInfo *mergee)
{
for (auto &param : mergee->params) {
if (param.first == id_MODE && base->params.count(id_MODE) && param.second.as_string() == "IREG_OREG")
continue; // mixed tristate register and I/ODDR
base->params[param.first] = param.second;
}
for (auto &port : mergee->ports) {
replace_port(mergee, port.first, base, port.first);
}
ctx->cells.erase(mergee->name);
}
void constrain_merge_iol()
{
dict<IdString, std::vector<CellInfo *>> io_to_iol;
for (auto &cell : ctx->cells) {
CellInfo *ci = cell.second.get();
if (ci->type != id_IOLOGIC)
continue;
CellInfo *iob = nullptr;
NetInfo *di = get_net_or_empty(ci, id_DI);
if (di != nullptr && di->driver.cell != nullptr)
iob = di->driver.cell;
NetInfo *dout = get_net_or_empty(ci, id_DOUT);
if (dout != nullptr && dout->users.size() == 1)
iob = dout->users.at(0).cell;
NetInfo *tout = get_net_or_empty(ci, id_DOUT);
if (tout != nullptr && tout->users.size() == 1)
iob = tout->users.at(0).cell;
if (iob->type != id_SEIO18_CORE && iob->type != id_SEIO33_CORE && iob->type != id_DIFFIO18_CORE)
log_error("Failed to find associated IOB for IOLOGIC %s\n", ctx->nameOf(ci));
io_to_iol[iob->name].push_back(ci);
}
for (auto &io_iol : io_to_iol) {
// Merge all IOLOGIC on an IO into a base IOLOGIC
CellInfo *iol = io_iol.second.at(0);
for (size_t i = 1; i < io_iol.second.size(); i++)
merge_iol_cell(iol, io_iol.second.at(i));
// Constrain, and update type if appropriate
CellInfo *iob = ctx->cells.at(io_iol.first).get();
if (iob->type == id_SEIO33_CORE)
iol->type = id_SIOLOGIC;
Loc iol_loc = ctx->getBelLocation(get_bel_attr(iob));
if (iob->type == id_DIFFIO18_CORE)
iol_loc.z = 3;
else
iol_loc.z += 3;
BelId iol_bel = ctx->getBelByLocation(iol_loc);
NPNR_ASSERT(iol_bel != BelId());
NPNR_ASSERT(ctx->getBelType(iol_bel) == iol->type);
log_info("Constraining IOLOGIC %s to bel %s\n", ctx->nameOf(iol), ctx->nameOfBel(iol_bel));
iol->attrs[id_BEL] = ctx->getBelName(iol_bel).str(ctx);
}
}
void pack_iologic()
{
log_info("Packing IOLOGIC...\n");
transform_iologic();
constrain_merge_iol();
}
void pack_widefn() void pack_widefn()
{ {
std::vector<CellInfo *> widefns; std::vector<CellInfo *> widefns;
@ -1994,6 +2080,7 @@ struct NexusPacker
void operator()() void operator()()
{ {
pack_io(); pack_io();
pack_iologic();
pack_dsps(); pack_dsps();
convert_prims(); convert_prims();
pack_bram(); pack_bram();

View File

@ -224,6 +224,10 @@ static const dict<IdString, Arch::CellPinsData> base_cell_pin_data = {
{id_LSROUT, PINSTYLE_IOL_CELSR}, {id_LSROUT, PINSTYLE_IOL_CELSR},
{id_CEIN, PINSTYLE_IOL_CELSR}, {id_CEIN, PINSTYLE_IOL_CELSR},
{id_CEOUT, PINSTYLE_IOL_CELSR}, {id_CEOUT, PINSTYLE_IOL_CELSR},
{id_TXDATA0, PINSTYLE_CIB},
{id_TXDATA1, PINSTYLE_CIB},
{id_TSDATA0, PINSTYLE_CIB},
}}, }},
{id_IOLOGIC, {id_IOLOGIC,
{ {
@ -233,6 +237,9 @@ static const dict<IdString, Arch::CellPinsData> base_cell_pin_data = {
{id_LSROUT, PINSTYLE_IOL_CELSR}, {id_LSROUT, PINSTYLE_IOL_CELSR},
{id_CEIN, PINSTYLE_IOL_CELSR}, {id_CEIN, PINSTYLE_IOL_CELSR},
{id_CEOUT, PINSTYLE_IOL_CELSR}, {id_CEOUT, PINSTYLE_IOL_CELSR},
{id_TXDATA0, PINSTYLE_CIB},
{id_TXDATA1, PINSTYLE_CIB},
{id_TSDATA0, PINSTYLE_CIB},
}}}; }}};
} // namespace } // namespace