Merge pull request #754 from YosysHQ/gatecat/ecp5-dcs
ecp5: Add DCSC support
This commit is contained in:
commit
bf542f07b0
12
ecp5/arch.cc
12
ecp5/arch.cc
@ -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;
|
||||||
|
@ -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);
|
||||||
|
@ -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)
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user