Merge pull request #754 from YosysHQ/gatecat/ecp5-dcs

ecp5: Add DCSC support
This commit is contained in:
gatecat 2021-07-06 14:06:31 +01:00 committed by GitHub
commit bf542f07b0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 55 additions and 11 deletions

View File

@ -793,6 +793,12 @@ bool Arch::getCellDelay(const CellInfo *cell, IdString fromPort, IdString toPort
return true; return true;
} }
return false; 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) { } else if (cell->type == id_DP16KD) {
return false; return false;
} else if (cell->type == id_MULT18X18D) { } else if (cell->type == id_MULT18X18D) {
@ -866,6 +872,12 @@ TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, in
if (port == id_CLKO) if (port == id_CLKO)
return TMG_COMB_OUTPUT; return TMG_COMB_OUTPUT;
return TMG_IGNORE; 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) { } else if (cell->type == id_DP16KD) {
if (port == id_CLKA || port == id_CLKB) if (port == id_CLKA || port == id_CLKB)
return TMG_CLOCK_INPUT; return TMG_CLOCK_INPUT;

View File

@ -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"); tg.config.add_enum(std::string("DCC_") + belname[0] + belname.substr(4) + ".MODE", "DCCA");
cc.tilegroups.push_back(tg); 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")) { } else if (ci->type == ctx->id("DP16KD")) {
TileGroup tg; TileGroup tg;
Loc loc = ctx->getBelLocation(ci->bel); Loc loc = ctx->getBelLocation(ci->bel);

View File

@ -1337,3 +1337,7 @@ X(IOLOGIC_MODE_ODDRX1F)
X(IOLOGIC_MODE_ODDRX2F) X(IOLOGIC_MODE_ODDRX2F)
X(IOLOGIC_MODE_OREG) X(IOLOGIC_MODE_OREG)
X(IOLOGIC_MODE_TSREG) X(IOLOGIC_MODE_TSREG)
X(DCSC)
X(DCSOUT)
X(MODESEL)

View File

@ -278,7 +278,7 @@ class Ecp5GlobalRouter
bool route_onto_global(NetInfo *net, int network) bool route_onto_global(NetInfo *net, int network)
{ {
WireId glb_src; 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); glb_src = ctx->getNetinfoSourceWire(net);
for (int quad = QUAD_UL; quad < QUAD_LR + 1; quad++) { for (int quad = QUAD_UL; quad < QUAD_LR + 1; quad++) {
WireId glb_dst = get_global_wire(GlobalQuadrant(quad), network); WireId glb_dst = get_global_wire(GlobalQuadrant(quad), network);
@ -293,7 +293,7 @@ class Ecp5GlobalRouter
// Get DCC wirelength based on source // Get DCC wirelength based on source
wirelen_t get_dcc_wirelen(CellInfo *dcc, bool &dedicated_routing) 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; BelId drv_bel;
const PortRef &drv = clki->driver; const PortRef &drv = clki->driver;
dedicated_routing = false; dedicated_routing = false;
@ -395,7 +395,7 @@ class Ecp5GlobalRouter
} }
// Attempt to place a DCC // Attempt to place a DCC
void place_dcc(CellInfo *dcc) void place_dcc_dcs(CellInfo *dcc)
{ {
BelId best_bel; BelId best_bel;
WireId best_bel_pclkcib; WireId best_bel_pclkcib;
@ -403,7 +403,7 @@ class Ecp5GlobalRouter
wirelen_t best_wirelen = 9999999; wirelen_t best_wirelen = 9999999;
bool dedicated_routing = false; bool dedicated_routing = false;
for (auto bel : ctx->getBels()) { 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(); std::string belname = ctx->loc_info(bel)->bel_data[bel.index].name.get();
if (belname.at(0) == 'D' && using_ce) if (belname.at(0) == 'D' && using_ce)
continue; // don't allow DCCs with CE at center continue; // don't allow DCCs with CE at center
@ -414,7 +414,7 @@ class Ecp5GlobalRouter
} }
wirelen_t wirelen = get_dcc_wirelen(dcc, dedicated_routing); wirelen_t wirelen = get_dcc_wirelen(dcc, dedicated_routing);
if (wirelen < best_wirelen) { if (wirelen < best_wirelen) {
if (dedicated_routing) { if (dedicated_routing || dcc->type == id_DCSC) {
best_bel_pclkcib = WireId(); best_bel_pclkcib = WireId();
} else { } else {
bool found_pclkcib = false; bool found_pclkcib = false;
@ -446,11 +446,11 @@ class Ecp5GlobalRouter
} }
// Insert a DCC into a net to promote it to a global // 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; NetInfo *glbptr = nullptr;
CellInfo *dccptr = 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) // Already have a DCC (such as clock gating)
glbptr = net; glbptr = net;
dccptr = net->driver.cell; dccptr = net->driver.cell;
@ -463,7 +463,10 @@ class Ecp5GlobalRouter
dcc->ports[id_CLKO].net = glbnet.get(); dcc->ports[id_CLKO].net = glbnet.get();
std::vector<PortRef> keep_users; std::vector<PortRef> keep_users;
for (auto user : net->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); keep_users.push_back(user);
} else if (net->driver.cell->type == id_EXTREFB && user.cell->type == id_DCUA) { } else if (net->driver.cell->type == id_EXTREFB && user.cell->type == id_DCUA) {
keep_users.push_back(user); keep_users.push_back(user);
@ -494,7 +497,7 @@ class Ecp5GlobalRouter
} }
glbptr->attrs[ctx->id("ECP5_IS_GLOBAL")] = 1; glbptr->attrs[ctx->id("ECP5_IS_GLOBAL")] = 1;
if (str_or_default(dccptr->attrs, ctx->id("BEL"), "") == "") if (str_or_default(dccptr->attrs, ctx->id("BEL"), "") == "")
place_dcc(dccptr); place_dcc_dcs(dccptr);
return glbptr; return glbptr;
} }
@ -524,6 +527,20 @@ class Ecp5GlobalRouter
else else
insert_dcc(clock); 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() void route_globals()
@ -539,8 +556,8 @@ class Ecp5GlobalRouter
dict<int, NetInfo *> clocks; dict<int, NetInfo *> clocks;
for (auto &cell : ctx->cells) { for (auto &cell : ctx->cells) {
CellInfo *ci = cell.second.get(); CellInfo *ci = cell.second.get();
if (ci->type == id_DCCA) { if (ci->type == id_DCCA || ci->type == id_DCSC) {
NetInfo *clock = ci->ports.at(id_CLKO).net; NetInfo *clock = ci->ports.at((ci->type == id_DCSC) ? id_DCSOUT : id_CLKO).net;
NPNR_ASSERT(clock != nullptr); NPNR_ASSERT(clock != nullptr);
bool drives_fabric = std::any_of(clock->users.begin(), clock->users.end(), bool drives_fabric = std::any_of(clock->users.begin(), clock->users.end(),
[this](const PortRef &port) { return !is_clock_port(port); }); [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); return global_route_priority(*a.first) < global_route_priority(*b.first);
}); });
for (const auto &user : toroute) { 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); route_logic_tile_global(clocks.at(user.second), user.second, *user.first);
} }
} }