aboutsummaryrefslogtreecommitdiffstats
path: root/ecp5
diff options
context:
space:
mode:
authorgatecat <gatecat@ds0.me>2021-07-06 11:45:27 +0100
committergatecat <gatecat@ds0.me>2021-07-06 11:45:37 +0100
commit81c549549d88640ed77fc2b1f3da52a10b4f93ce (patch)
tree76a618926561d9cb1ae2e3b13cf588731514736d /ecp5
parent8a9fb810369aeb5eed128ef4e7d4de456ef1ec8f (diff)
downloadnextpnr-81c549549d88640ed77fc2b1f3da52a10b4f93ce.tar.gz
nextpnr-81c549549d88640ed77fc2b1f3da52a10b4f93ce.tar.bz2
nextpnr-81c549549d88640ed77fc2b1f3da52a10b4f93ce.zip
ecp5: Add DCSC support
Signed-off-by: gatecat <gatecat@ds0.me>
Diffstat (limited to 'ecp5')
-rw-r--r--ecp5/arch.cc12
-rw-r--r--ecp5/bitstream.cc5
-rw-r--r--ecp5/constids.inc4
-rw-r--r--ecp5/globals.cc45
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<std::string> 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<PortRef> 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<CellInfo *> 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<int, NetInfo *> 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);
}
}