diff options
author | David Shah <dave@ds0.me> | 2019-09-03 11:53:50 +0100 |
---|---|---|
committer | David Shah <dave@ds0.me> | 2019-09-03 11:53:50 +0100 |
commit | de5d22fbd89b2aee98dba25bb970a50b48998110 (patch) | |
tree | be6d1d7e9c449dff3a420bb5c6f8544b743eb15c | |
parent | 4d8fa130334376640432a7b5d371cd0bfae46cb5 (diff) | |
parent | c0b7379e8672b6263152d5e340e62f22179fdc8b (diff) | |
download | nextpnr-de5d22fbd89b2aee98dba25bb970a50b48998110.tar.gz nextpnr-de5d22fbd89b2aee98dba25bb970a50b48998110.tar.bz2 nextpnr-de5d22fbd89b2aee98dba25bb970a50b48998110.zip |
Merge branch 'master' of ssh.github.com:YosysHQ/nextpnr
-rw-r--r-- | ecp5/arch.cc | 20 | ||||
-rw-r--r-- | ecp5/arch.h | 1 | ||||
-rw-r--r-- | ecp5/bitstream.cc | 32 | ||||
-rw-r--r-- | ecp5/globals.cc | 96 |
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; } |