aboutsummaryrefslogtreecommitdiffstats
path: root/ecp5
diff options
context:
space:
mode:
authorDavid Shah <dave@ds0.me>2019-02-13 11:23:12 +0000
committerDavid Shah <davey1576@gmail.com>2019-02-24 10:28:25 +0100
commit68abcb365a7e1c426d2ca96e2381892aa53e6192 (patch)
treef53e92b404e6abfb79519eb93cc31d04f20f898d /ecp5
parent49e945382038e71f35619bf94a24f0008164e57b (diff)
downloadnextpnr-68abcb365a7e1c426d2ca96e2381892aa53e6192.tar.gz
nextpnr-68abcb365a7e1c426d2ca96e2381892aa53e6192.tar.bz2
nextpnr-68abcb365a7e1c426d2ca96e2381892aa53e6192.zip
ecp5: Add ECLKSYNCB support
Signed-off-by: David Shah <dave@ds0.me>
Diffstat (limited to 'ecp5')
-rw-r--r--ecp5/arch.cc4
-rw-r--r--ecp5/bitstream.cc7
-rw-r--r--ecp5/pack.cc25
3 files changed, 34 insertions, 2 deletions
diff --git a/ecp5/arch.cc b/ecp5/arch.cc
index 81f9682c..7de5c7aa 100644
--- a/ecp5/arch.cc
+++ b/ecp5/arch.cc
@@ -765,6 +765,10 @@ TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, in
return (cell->ports.at(port).type == PORT_OUT) ? TMG_STARTPOINT : TMG_ENDPOINT;
} else if (cell->type == id_TRELLIS_ECLKBUF) {
return (cell->ports.at(port).type == PORT_OUT) ? TMG_COMB_OUTPUT : TMG_COMB_INPUT;
+ } else if (cell->type == id_ECLKSYNCB) {
+ if (cell->ports.at(port).name == id_STOP)
+ return TMG_ENDPOINT;
+ return (cell->ports.at(port).type == PORT_OUT) ? TMG_COMB_OUTPUT : TMG_COMB_INPUT;
} else {
log_error("cell type '%s' is unsupported (instantiated as '%s')\n", cell->type.c_str(this),
cell->name.c_str(this));
diff --git a/ecp5/bitstream.cc b/ecp5/bitstream.cc
index 789957c6..c433a088 100644
--- a/ecp5/bitstream.cc
+++ b/ecp5/bitstream.cc
@@ -1221,6 +1221,13 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex
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 if (ci->type == id_ECLKSYNCB) {
+ Loc loc = ctx->getBelLocation(ci->bel);
+ bool r = loc.x > 5;
+ std::string eclksync = ctx->locInfo(bel)->bel_data[bel.index].name.get();
+ std::string tile = ctx->getTileByType(std::string("ECLK_") + (r ? "R" : "L"));
+ if (get_net_or_empty(ci, id_STOP) != nullptr)
+ cc.tiles[tile].add_enum(eclksync + ".MODE", "ECLKSYNCB");
} else {
NPNR_ASSERT_FALSE("unsupported cell type");
}
diff --git a/ecp5/pack.cc b/ecp5/pack.cc
index 17b0ea3b..b84d4d60 100644
--- a/ecp5/pack.cc
+++ b/ecp5/pack.cc
@@ -1958,11 +1958,32 @@ class Ecp5Packer
continue;
ci->attrs[ctx->id("BEL")] = ctx->getBelName(bel).str(ctx);
make_eclk(ci->ports.at(id_CLKI), ci, bel, eclk.first.first);
- goto done;
+ goto clkdiv_done;
}
}
}
- done:
+ clkdiv_done:
+ continue;
+ } else if (ci->type == id_ECLKSYNCB) {
+ const NetInfo *eclko = net_or_nullptr(ci, id_ECLKO);
+ if (eclko == nullptr)
+ log_error("ECLKSYNCB '%s' has disconnected port ECLKO\n", ci->name.c_str(ctx));
+ for (auto user : eclko->users) {
+ if (user.cell->type == id_TRELLIS_ECLKBUF) {
+ Loc eckbuf_loc =
+ ctx->getBelLocation(ctx->getBelByName(ctx->id(user.cell->attrs.at(ctx->id("BEL")))));
+ for (auto bel : ctx->getBels()) {
+ if (ctx->getBelType(bel) != id_ECLKSYNCB)
+ continue;
+ Loc loc = ctx->getBelLocation(bel);
+ if (loc.x == eckbuf_loc.x && loc.y == eckbuf_loc.y && loc.z == eckbuf_loc.z - 2) {
+ ci->attrs[ctx->id("BEL")] = ctx->getBelName(bel).str(ctx);
+ goto eclksync_done;
+ }
+ }
+ }
+ }
+ eclksync_done:
continue;
}
}