aboutsummaryrefslogtreecommitdiffstats
path: root/nexus
diff options
context:
space:
mode:
authorgatecat <gatecat@ds0.me>2021-07-28 13:18:38 +0100
committergatecat <gatecat@ds0.me>2021-07-28 13:27:02 +0100
commit5686fdcf1c4cc5cd7f75ef296f64673f0f679d4e (patch)
treed38296f9a6122bd2bb3abbe19507dacd337c92f4 /nexus
parentd0acb1b2391fb33f0888778a4c644058076343ee (diff)
downloadnextpnr-5686fdcf1c4cc5cd7f75ef296f64673f0f679d4e.tar.gz
nextpnr-5686fdcf1c4cc5cd7f75ef296f64673f0f679d4e.tar.bz2
nextpnr-5686fdcf1c4cc5cd7f75ef296f64673f0f679d4e.zip
nexus: Basic packer and FASM support for I/ODDR
Signed-off-by: gatecat <gatecat@ds0.me>
Diffstat (limited to 'nexus')
-rw-r--r--nexus/constids.inc14
-rw-r--r--nexus/fasm.cc18
-rw-r--r--nexus/pack.cc87
-rw-r--r--nexus/pins.cc7
4 files changed, 124 insertions, 2 deletions
diff --git a/nexus/constids.inc b/nexus/constids.inc
index 98817899..5407cb23 100644
--- a/nexus/constids.inc
+++ b/nexus/constids.inc
@@ -514,3 +514,17 @@ X(SCLKIN)
X(SCLKOUT)
X(ECLK)
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)
diff --git a/nexus/fasm.cc b/nexus/fasm.cc
index 6715af47..aea57d6a 100644
--- a/nexus/fasm.cc
+++ b/nexus/fasm.cc
@@ -257,11 +257,11 @@ struct NexusFasmWriter
if (pin_style & PINOPT_INV) {
if (pin_mux == PINMUX_INV || pin_mux == PINMUX_0)
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)));
}
// 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)));
// Pins that must be explictly set to 1 rather than just left floating
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));
}
+ // 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
void write_dsp(const CellInfo *cell)
{
@@ -872,6 +884,8 @@ struct NexusFasmWriter
write_lram(ci);
else if (ci->type == id_DPHY_CORE)
write_dphy(ci);
+ else if (ci->type == id_IOLOGIC || ci->type == id_SIOLOGIC)
+ write_iol(ci);
blank();
}
// Handle DCC route-throughs
diff --git a/nexus/pack.cc b/nexus/pack.cc
index 6b310d64..6385121b 100644
--- a/nexus/pack.cc
+++ b/nexus/pack.cc
@@ -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()
{
std::vector<CellInfo *> widefns;
@@ -1994,6 +2080,7 @@ struct NexusPacker
void operator()()
{
pack_io();
+ pack_iologic();
pack_dsps();
convert_prims();
pack_bram();
diff --git a/nexus/pins.cc b/nexus/pins.cc
index e1012755..03bddd72 100644
--- a/nexus/pins.cc
+++ b/nexus/pins.cc
@@ -224,6 +224,10 @@ static const dict<IdString, Arch::CellPinsData> base_cell_pin_data = {
{id_LSROUT, PINSTYLE_IOL_CELSR},
{id_CEIN, PINSTYLE_IOL_CELSR},
{id_CEOUT, PINSTYLE_IOL_CELSR},
+ {id_TXDATA0, PINSTYLE_CIB},
+ {id_TXDATA1, PINSTYLE_CIB},
+ {id_TSDATA0, PINSTYLE_CIB},
+
}},
{id_IOLOGIC,
{
@@ -233,6 +237,9 @@ static const dict<IdString, Arch::CellPinsData> base_cell_pin_data = {
{id_LSROUT, PINSTYLE_IOL_CELSR},
{id_CEIN, PINSTYLE_IOL_CELSR},
{id_CEOUT, PINSTYLE_IOL_CELSR},
+ {id_TXDATA0, PINSTYLE_CIB},
+ {id_TXDATA1, PINSTYLE_CIB},
+ {id_TSDATA0, PINSTYLE_CIB},
}}};
} // namespace