From 81c549549d88640ed77fc2b1f3da52a10b4f93ce Mon Sep 17 00:00:00 2001 From: gatecat Date: Tue, 6 Jul 2021 11:45:27 +0100 Subject: ecp5: Add DCSC support Signed-off-by: gatecat --- ecp5/arch.cc | 12 ++++++++++++ ecp5/bitstream.cc | 5 +++++ ecp5/constids.inc | 4 ++++ ecp5/globals.cc | 45 ++++++++++++++++++++++++++++++++++----------- 4 files changed, 55 insertions(+), 11 deletions(-) diff --git a/ecp5/arch.cc b/ecp5/arch.cc index 2c04105c..34bdfa1b 100644 --- a/ecp5/arch.cc +++ b/ecp5/arch.cc @@ -793,6 +793,12 @@ bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort return true; } return false; + } else if (cell->type == id_DCSC) { + if ((fromPort == id_CLK0 || fromPort == id_CLK1) && toPort == id_DCSOUT) { + delay = DelayQuad(0); + return true; + } + return false; } else if (cell->type == id_DP16KD) { return false; } else if (cell->type == id_MULT18X18D) { @@ -866,6 +872,12 @@ TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, in if (port == id_CLKO) return TMG_COMB_OUTPUT; return TMG_IGNORE; + } else if (cell->type == id_DCSC) { + if (port == id_CLK0 || port == id_CLK1) + return TMG_COMB_INPUT; + if (port == id_DCSOUT) + return TMG_COMB_OUTPUT; + return TMG_IGNORE; } else if (cell->type == id_DP16KD) { if (port == id_CLKA || port == id_CLKB) return TMG_CLOCK_INPUT; diff --git a/ecp5/bitstream.cc b/ecp5/bitstream.cc index c92de083..a544f2b7 100644 --- a/ecp5/bitstream.cc +++ b/ecp5/bitstream.cc @@ -1019,6 +1019,11 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex 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("DCSC")) { + std::set dcs_tiles{"EBR_CMUX_LL", "EBR_CMUX_UL", "EBR_CMUX_LL_25K", "DSP_CMUX_UL"}; + std::string tile = ctx->get_tile_by_type_loc(bel.location.y, bel.location.x, dcs_tiles); + std::string dcs = ctx->loc_info(bel)->bel_data[bel.index].name.get(); + cc.tiles[tile].add_enum(dcs + ".DCSMODE", str_or_default(ci->attrs, ctx->id("DCSMODE"), "POS")); } else if (ci->type == ctx->id("DP16KD")) { TileGroup tg; Loc loc = ctx->getBelLocation(ci->bel); diff --git a/ecp5/constids.inc b/ecp5/constids.inc index e5ec1c3e..335f822a 100644 --- a/ecp5/constids.inc +++ b/ecp5/constids.inc @@ -1337,3 +1337,7 @@ X(IOLOGIC_MODE_ODDRX1F) X(IOLOGIC_MODE_ODDRX2F) X(IOLOGIC_MODE_OREG) X(IOLOGIC_MODE_TSREG) + +X(DCSC) +X(DCSOUT) +X(MODESEL) diff --git a/ecp5/globals.cc b/ecp5/globals.cc index 580d470a..8ee49c02 100644 --- a/ecp5/globals.cc +++ b/ecp5/globals.cc @@ -278,7 +278,7 @@ class Ecp5GlobalRouter bool route_onto_global(NetInfo *net, int network) { WireId glb_src; - NPNR_ASSERT(net->driver.cell->type == id_DCCA); + NPNR_ASSERT(net->driver.cell->type == id_DCCA || net->driver.cell->type == id_DCSC); glb_src = ctx->getNetinfoSourceWire(net); for (int quad = QUAD_UL; quad < QUAD_LR + 1; quad++) { WireId glb_dst = get_global_wire(GlobalQuadrant(quad), network); @@ -293,7 +293,7 @@ class Ecp5GlobalRouter // Get DCC wirelength based on source wirelen_t get_dcc_wirelen(CellInfo *dcc, bool &dedicated_routing) { - NetInfo *clki = dcc->ports.at(id_CLKI).net; + NetInfo *clki = dcc->ports.at((dcc->type == id_DCSC) ? id_CLK0 : id_CLKI).net; BelId drv_bel; const PortRef &drv = clki->driver; dedicated_routing = false; @@ -395,7 +395,7 @@ class Ecp5GlobalRouter } // Attempt to place a DCC - void place_dcc(CellInfo *dcc) + void place_dcc_dcs(CellInfo *dcc) { BelId best_bel; WireId best_bel_pclkcib; @@ -403,7 +403,7 @@ class Ecp5GlobalRouter wirelen_t best_wirelen = 9999999; bool dedicated_routing = false; for (auto bel : ctx->getBels()) { - if (ctx->getBelType(bel) == id_DCCA && ctx->checkBelAvail(bel)) { + if (ctx->getBelType(bel) == dcc->type && ctx->checkBelAvail(bel)) { std::string belname = ctx->loc_info(bel)->bel_data[bel.index].name.get(); if (belname.at(0) == 'D' && using_ce) continue; // don't allow DCCs with CE at center @@ -414,7 +414,7 @@ class Ecp5GlobalRouter } wirelen_t wirelen = get_dcc_wirelen(dcc, dedicated_routing); if (wirelen < best_wirelen) { - if (dedicated_routing) { + if (dedicated_routing || dcc->type == id_DCSC) { best_bel_pclkcib = WireId(); } else { bool found_pclkcib = false; @@ -446,11 +446,11 @@ class Ecp5GlobalRouter } // Insert a DCC into a net to promote it to a global - NetInfo *insert_dcc(NetInfo *net) + NetInfo *insert_dcc(NetInfo *net, CellInfo *dcs_cell = nullptr) { NetInfo *glbptr = nullptr; CellInfo *dccptr = nullptr; - if (net->driver.cell != nullptr && net->driver.cell->type == id_DCCA) { + if (net->driver.cell != nullptr && (net->driver.cell->type == id_DCCA || net->driver.cell->type == id_DCSC)) { // Already have a DCC (such as clock gating) glbptr = net; dccptr = net->driver.cell; @@ -463,7 +463,10 @@ class Ecp5GlobalRouter dcc->ports[id_CLKO].net = glbnet.get(); std::vector keep_users; for (auto user : net->users) { - if (user.port == id_CLKFB) { + if (dcs_cell != nullptr && user.cell != dcs_cell) { + // DCS DCC insertion mode + keep_users.push_back(user); + } else 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); @@ -494,7 +497,7 @@ class Ecp5GlobalRouter } glbptr->attrs[ctx->id("ECP5_IS_GLOBAL")] = 1; if (str_or_default(dccptr->attrs, ctx->id("BEL"), "") == "") - place_dcc(dccptr); + place_dcc_dcs(dccptr); return glbptr; } @@ -524,6 +527,20 @@ class Ecp5GlobalRouter else insert_dcc(clock); } + // Insert DCCs on DCS inputs, too + std::vector dcsc_cells; + for (auto &cell : ctx->cells) { + CellInfo *ci = cell.second.get(); + if (ci->type == id_DCSC) + dcsc_cells.push_back(ci); + } + for (auto ci : dcsc_cells) { + for (auto port : {id_CLK0, id_CLK1}) { + NetInfo *net = get_net_or_empty(ci, port); + if (net != nullptr) + insert_dcc(net, ci); + } + } } void route_globals() @@ -539,8 +556,8 @@ class Ecp5GlobalRouter dict clocks; for (auto &cell : ctx->cells) { CellInfo *ci = cell.second.get(); - if (ci->type == id_DCCA) { - NetInfo *clock = ci->ports.at(id_CLKO).net; + if (ci->type == id_DCCA || ci->type == id_DCSC) { + NetInfo *clock = ci->ports.at((ci->type == id_DCSC) ? id_DCSOUT : id_CLKO).net; NPNR_ASSERT(clock != nullptr); bool drives_fabric = std::any_of(clock->users.begin(), clock->users.end(), [this](const PortRef &port) { return !is_clock_port(port); }); @@ -571,6 +588,12 @@ class Ecp5GlobalRouter return global_route_priority(*a.first) < global_route_priority(*b.first); }); for (const auto &user : toroute) { + if (user.first->cell->type == id_DCSC && (user.first->port == id_CLK0 || user.first->port == id_CLK1)) { + // Special case, skips most of the typical global network + NetInfo *net = clocks.at(user.second); + simple_router(net, ctx->getNetinfoSourceWire(net), ctx->getNetinfoSinkWire(net, *(user.first), 0)); + continue; + } route_logic_tile_global(clocks.at(user.second), user.second, *user.first); } } -- cgit v1.2.3