aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Shah <dave@ds0.me>2019-09-03 11:53:50 +0100
committerDavid Shah <dave@ds0.me>2019-09-03 11:53:50 +0100
commitde5d22fbd89b2aee98dba25bb970a50b48998110 (patch)
treebe6d1d7e9c449dff3a420bb5c6f8544b743eb15c
parent4d8fa130334376640432a7b5d371cd0bfae46cb5 (diff)
parentc0b7379e8672b6263152d5e340e62f22179fdc8b (diff)
downloadnextpnr-de5d22fbd89b2aee98dba25bb970a50b48998110.tar.gz
nextpnr-de5d22fbd89b2aee98dba25bb970a50b48998110.tar.bz2
nextpnr-de5d22fbd89b2aee98dba25bb970a50b48998110.zip
Merge branch 'master' of ssh.github.com:YosysHQ/nextpnr
-rw-r--r--ecp5/arch.cc20
-rw-r--r--ecp5/arch.h1
-rw-r--r--ecp5/bitstream.cc32
-rw-r--r--ecp5/globals.cc96
4 files changed, 110 insertions, 39 deletions
diff --git a/ecp5/arch.cc b/ecp5/arch.cc
index a2936688..8ba1af4d 100644
--- a/ecp5/arch.cc
+++ b/ecp5/arch.cc
@@ -158,6 +158,26 @@ std::string Arch::getChipName() const
}
}
+std::string Arch::getFullChipName() const
+{
+ std::string name = getChipName();
+ name += "-";
+ switch (args.speed) {
+ case ArchArgs::SPEED_6:
+ name += "6";
+ break;
+ case ArchArgs::SPEED_7:
+ name += "7";
+ break;
+ case ArchArgs::SPEED_8:
+ case ArchArgs::SPEED_8_5G:
+ name += "8";
+ break;
+ }
+ name += args.package;
+ return name;
+}
+
// -----------------------------------------------------------------------
IdString Arch::archArgsToId(ArchArgs args) const
diff --git a/ecp5/arch.h b/ecp5/arch.h
index e85d9c43..a479abb6 100644
--- a/ecp5/arch.h
+++ b/ecp5/arch.h
@@ -491,6 +491,7 @@ struct Arch : BaseCtx
Arch(ArchArgs args);
std::string getChipName() const;
+ std::string getFullChipName() const;
IdString archId() const { return id("ecp5"); }
ArchArgs archArgs() const { return args; }
diff --git a/ecp5/bitstream.cc b/ecp5/bitstream.cc
index cac11867..f010d7dd 100644
--- a/ecp5/bitstream.cc
+++ b/ecp5/bitstream.cc
@@ -600,6 +600,8 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex
}
}
+ cc.metadata.push_back("Part: " + ctx->getFullChipName());
+
// Clear out DCU tieoffs in base config if DCU used
for (auto &cell : ctx->cells) {
CellInfo *ci = cell.second.get();
@@ -890,7 +892,35 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex
if (datamux_mddr != "PADDO")
cc.tiles[pic_tile].add_enum(pio + ".DATAMUX_MDDR", datamux_mddr);
} else if (ci->type == ctx->id("DCCA")) {
- // Nothing to do
+ const NetInfo *cen = get_net_or_empty(ci, ctx->id("CE"));
+ if (cen != nullptr) {
+ std::string belname = ctx->locInfo(bel)->bel_data[bel.index].name.get();
+ Loc loc = ctx->getBelLocation(bel);
+ TileGroup tg;
+ switch (belname[0]) {
+ case 'B':
+ tg.tiles.push_back(
+ ctx->getTileByTypeAndLocation(loc.y, loc.x, std::set<std::string>{"BMID_0H", "BMID_0V"}));
+ tg.tiles.push_back(ctx->getTileByTypeAndLocation(loc.y, loc.x + 1,
+ std::set<std::string>{"BMID_2", "BMID_2V"}));
+ break;
+ case 'T':
+ tg.tiles.push_back(ctx->getTileByTypeAndLocation(loc.y, loc.x, "TMID_0"));
+ tg.tiles.push_back(ctx->getTileByTypeAndLocation(loc.y, loc.x + 1, "TMID_1"));
+ break;
+ case 'L':
+ tg.tiles.push_back(ctx->getTileByTypeAndLocation(loc.y, loc.x, "LMID_0"));
+ break;
+ case 'R':
+ tg.tiles.push_back(ctx->getTileByTypeAndLocation(loc.y, loc.x, "RMID_0"));
+ break;
+ default:
+ NPNR_ASSERT_FALSE("bad DCC for gating");
+ break;
+ }
+ tg.config.add_enum(std::string("DCC_") + belname[0] + belname.substr(4) + ".MODE", "DCCA");
+ cc.tilegroups.push_back(tg);
+ }
} else if (ci->type == ctx->id("DP16KD")) {
TileGroup tg;
Loc loc = ctx->getBelLocation(ci->bel);
diff --git a/ecp5/globals.cc b/ecp5/globals.cc
index bc5c66df..da2ba8f0 100644
--- a/ecp5/globals.cc
+++ b/ecp5/globals.cc
@@ -78,7 +78,18 @@ class Ecp5GlobalRouter
}
// log_info("clkcount %s: %d\n", ni->name.c_str(ctx),clockCount[ni->name]);
}
+ // DCCAs must always drive globals
std::vector<NetInfo *> clocks;
+ for (auto &cell : sorted(ctx->cells)) {
+ CellInfo *ci = cell.second;
+ if (ci->type == id_DCCA) {
+ NetInfo *glb = ci->ports.at(id_CLKO).net;
+ if (glb != nullptr) {
+ clocks.push_back(glb);
+ clockCount.erase(glb->name);
+ }
+ }
+ }
while (clocks.size() < 16) {
auto max = std::max_element(clockCount.begin(), clockCount.end(),
[](const decltype(clockCount)::value_type &a,
@@ -355,10 +366,14 @@ class Ecp5GlobalRouter
void place_dcc(CellInfo *dcc)
{
BelId best_bel;
+ bool using_ce = get_net_or_empty(dcc, ctx->id("CE")) != nullptr;
wirelen_t best_wirelen = 9999999;
for (auto bel : ctx->getBels()) {
if (ctx->getBelType(bel) == id_DCCA && ctx->checkBelAvail(bel)) {
if (ctx->isValidBelForCell(dcc, bel)) {
+ std::string belname = ctx->locInfo(bel)->bel_data[bel.index].name.get();
+ if (belname.at(0) == 'D' && using_ce)
+ continue; // don't allow DCCs with CE at center
ctx->bindBel(bel, dcc, STRENGTH_LOCKED);
wirelen_t wirelen = get_dcc_wirelen(dcc);
if (wirelen < best_wirelen) {
@@ -376,46 +391,51 @@ class Ecp5GlobalRouter
// Insert a DCC into a net to promote it to a global
NetInfo *insert_dcc(NetInfo *net)
{
- auto dcc = create_ecp5_cell(ctx, id_DCCA, "$gbuf$" + net->name.str(ctx));
-
- std::unique_ptr<NetInfo> glbnet = std::unique_ptr<NetInfo>(new NetInfo);
- glbnet->name = ctx->id("$glbnet$" + net->name.str(ctx));
- glbnet->driver.cell = dcc.get();
- glbnet->driver.port = id_CLKO;
- glbnet->attrs[ctx->id("ECP5_IS_GLOBAL")] = 1;
- dcc->ports[id_CLKO].net = glbnet.get();
-
- std::vector<PortRef> keep_users;
- for (auto user : net->users) {
- if (user.port == id_CLKFB) {
- keep_users.push_back(user);
- } else if (net->driver.cell->type == id_EXTREFB && user.cell->type == id_DCUA) {
- keep_users.push_back(user);
- } else {
- glbnet->users.push_back(user);
- user.cell->ports.at(user.port).net = glbnet.get();
+ NetInfo *glbptr = nullptr;
+ CellInfo *dccptr = nullptr;
+ if (net->driver.cell != nullptr && net->driver.cell->type == id_DCCA) {
+ // Already have a DCC (such as clock gating)
+ glbptr = net;
+ dccptr = net->driver.cell;
+ } else {
+ auto dcc = create_ecp5_cell(ctx, id_DCCA, "$gbuf$" + net->name.str(ctx));
+ std::unique_ptr<NetInfo> glbnet = std::unique_ptr<NetInfo>(new NetInfo);
+ glbnet->name = ctx->id("$glbnet$" + net->name.str(ctx));
+ glbnet->driver.cell = dcc.get();
+ glbnet->driver.port = id_CLKO;
+ dcc->ports[id_CLKO].net = glbnet.get();
+ std::vector<PortRef> keep_users;
+ for (auto user : net->users) {
+ if (user.port == id_CLKFB) {
+ keep_users.push_back(user);
+ } else if (net->driver.cell->type == id_EXTREFB && user.cell->type == id_DCUA) {
+ keep_users.push_back(user);
+ } else {
+ glbnet->users.push_back(user);
+ user.cell->ports.at(user.port).net = glbnet.get();
+ }
}
+ net->users = keep_users;
+
+ dcc->ports[id_CLKI].net = net;
+ PortRef clki_pr;
+ clki_pr.port = id_CLKI;
+ clki_pr.cell = dcc.get();
+ net->users.push_back(clki_pr);
+ if (net->clkconstr) {
+ glbnet->clkconstr = std::unique_ptr<ClockConstraint>(new ClockConstraint());
+ glbnet->clkconstr->low = net->clkconstr->low;
+ glbnet->clkconstr->high = net->clkconstr->high;
+ glbnet->clkconstr->period = net->clkconstr->period;
+ }
+ glbptr = glbnet.get();
+ ctx->nets[glbnet->name] = std::move(glbnet);
+ dccptr = dcc.get();
+ ctx->cells[dcc->name] = std::move(dcc);
}
- net->users = keep_users;
-
- dcc->ports[id_CLKI].net = net;
- PortRef clki_pr;
- clki_pr.port = id_CLKI;
- clki_pr.cell = dcc.get();
- net->users.push_back(clki_pr);
-
- place_dcc(dcc.get());
-
- if (net->clkconstr) {
- glbnet->clkconstr = std::unique_ptr<ClockConstraint>(new ClockConstraint());
- glbnet->clkconstr->low = net->clkconstr->low;
- glbnet->clkconstr->high = net->clkconstr->high;
- glbnet->clkconstr->period = net->clkconstr->period;
- }
-
- ctx->cells[dcc->name] = std::move(dcc);
- NetInfo *glbptr = glbnet.get();
- ctx->nets[glbnet->name] = std::move(glbnet);
+ glbptr->attrs[ctx->id("ECP5_IS_GLOBAL")] = 1;
+ if (str_or_default(dccptr->attrs, ctx->id("BEL"), "") == "")
+ place_dcc(dccptr);
return glbptr;
}