aboutsummaryrefslogtreecommitdiffstats
path: root/nexus/pack.cc
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/pack.cc
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/pack.cc')
-rw-r--r--nexus/pack.cc87
1 files changed, 87 insertions, 0 deletions
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();