Cover more global routing cases
This commit is contained in:
parent
ca2751277d
commit
5d5be7df63
@ -94,6 +94,9 @@ CellInfo *NgUltraPacker::create_cell_ptr(IdString type, IdString name)
|
||||
add_port("CKO1", PORT_OUT);
|
||||
add_port("P19RI", PORT_IN);
|
||||
add_port("CKO2", PORT_OUT);
|
||||
} else if (type == id_WFB) {
|
||||
add_port("ZI", PORT_IN);
|
||||
add_port("ZO", PORT_OUT);
|
||||
} else {
|
||||
log_error("Trying to create unknown cell type %s\n", type.c_str(ctx));
|
||||
}
|
||||
|
@ -91,7 +91,9 @@ int NgUltraImpl::tile_lobe(int tile) const
|
||||
|
||||
void NgUltraImpl::preRoute()
|
||||
{
|
||||
log_break();
|
||||
route_clocks();
|
||||
log_break();
|
||||
}
|
||||
|
||||
bool NgUltraImpl::get_mux_data(BelId bel, IdString port, uint8_t *value)
|
||||
|
@ -969,26 +969,14 @@ void NgUltraPacker::pack_rfs(void)
|
||||
flush_cells();
|
||||
}
|
||||
|
||||
// There are 20 dedicated clock inputs capable of being routed using global network
|
||||
// to be able to best route them, IOM needs to be used to propagate these clock signals
|
||||
void NgUltraPacker::promote_globals()
|
||||
void NgUltraPacker::insert_ioms()
|
||||
{
|
||||
std::vector<std::pair<int, IdString>> glb_fanout;
|
||||
int available_globals = 20;
|
||||
std::vector<IdString> pins_needing_iom;
|
||||
for (auto &net : ctx->nets) {
|
||||
NetInfo *ni = net.second.get();
|
||||
// Skip undriven nets; and nets that are already global
|
||||
// Skip undriven nets
|
||||
if (ni->driver.cell == nullptr)
|
||||
continue;
|
||||
if (ni->name.in(ctx->id("$PACKER_GND_NET"), ctx->id("$PACKER_VCC_NET")))
|
||||
continue;
|
||||
if (ni->driver.cell->type == id_IOM) {
|
||||
continue;
|
||||
}
|
||||
if (ni->driver.cell->type == id_GCK) {
|
||||
--available_globals;
|
||||
continue;
|
||||
}
|
||||
if (!ni->driver.cell->type.in(id_BFR)) {
|
||||
continue;
|
||||
}
|
||||
@ -997,25 +985,18 @@ void NgUltraPacker::promote_globals()
|
||||
BelId bel = ctx->getBelByLocation(iotp_loc);
|
||||
if (uarch->global_capable_bels.count(bel)==0)
|
||||
continue;
|
||||
// Count the number of clock ports
|
||||
int glb_count = 0;
|
||||
for (const auto &usr : ni->users) {
|
||||
if (clock_sinks.count(usr.cell->type) && clock_sinks[usr.cell->type].count(usr.port))
|
||||
glb_count++;
|
||||
if (clock_sinks.count(usr.cell->type) && clock_sinks[usr.cell->type].count(usr.port)) {
|
||||
pins_needing_iom.emplace_back(ni->name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (glb_count > 0)
|
||||
glb_fanout.emplace_back(glb_count, ni->name);
|
||||
}
|
||||
if (available_globals <= 0)
|
||||
return;
|
||||
// Sort clocks by max fanout
|
||||
std::sort(glb_fanout.begin(), glb_fanout.end(), std::greater<std::pair<int, IdString>>());
|
||||
log_info("Promoting globals...\n");
|
||||
log_info("Inserting IOMs...\n");
|
||||
int bfr_removed = 0;
|
||||
// Promote the N highest fanout clocks
|
||||
for (size_t i = 0; i < std::min<size_t>(glb_fanout.size(), available_globals); i++) {
|
||||
NetInfo *net = ctx->nets.at(glb_fanout.at(i).second).get();
|
||||
log_info(" Promoting clock net '%s'\n", ctx->nameOf(net));
|
||||
for (size_t i = 0; i < pins_needing_iom.size(); i++) {
|
||||
NetInfo *net = ctx->nets.at(pins_needing_iom.at(i)).get();
|
||||
Loc iotp_loc = net->driver.cell->getLocation();
|
||||
iotp_loc.z -= 1;
|
||||
BelId iotp_bel = ctx->getBelByLocation(iotp_loc);
|
||||
@ -1025,25 +1006,27 @@ void NgUltraPacker::promote_globals()
|
||||
|
||||
CellInfo *iom = nullptr;
|
||||
IdString port = uarch->global_capable_bels.at(iotp_bel);
|
||||
CellInfo *input_pad = ctx->getBoundBelCell(iotp_bel);
|
||||
std::string iobname = str_or_default(input_pad->params, ctx->id("iobname"), "");
|
||||
if (!ctx->checkBelAvail(bel)) {
|
||||
iom = ctx->getBoundBelCell(bel);
|
||||
log_info(" Reusing IOM in bank '%s' for signal '%s'\n", iob.c_str(ctx), iobname.c_str());
|
||||
} else {
|
||||
iom = create_cell_ptr(id_IOM, ctx->id(std::string(iob.c_str(ctx)) + "$iom"));
|
||||
log_info(" Adding IOM in bank '%s' for signal '%s'\n", iob.c_str(ctx), iobname.c_str());
|
||||
}
|
||||
if (iom->getPort(port)) {
|
||||
log_error("Port '%s' of IOM cell '%s' is already used.\n", port.c_str(ctx), iom->name.c_str(ctx));
|
||||
}
|
||||
CellInfo *input_pad = ctx->getBoundBelCell(iotp_bel);
|
||||
NetInfo *iom_to_clk = ctx->createNet(ctx->id(std::string(net->name.c_str(ctx)) + "$iom"));
|
||||
for (const auto &usr : net->users) {
|
||||
if (clock_sinks.count(usr.cell->type) && clock_sinks[usr.cell->type].count(usr.port)) {
|
||||
IdString port = usr.port;
|
||||
usr.cell->disconnectPort(port);
|
||||
usr.cell->connectPort(port, iom_to_clk);
|
||||
}
|
||||
}
|
||||
iom->connectPort(port, input_pad->getPort(id_O));
|
||||
iom->connectPort((port==id_P17RI) ? id_CKO1 : id_CKO2, iom_to_clk);
|
||||
if (ctx->checkBelAvail(bel))
|
||||
ctx->bindBel(bel, iom, PlaceStrength::STRENGTH_LOCKED);
|
||||
CellInfo *bfr = net->driver.cell;
|
||||
if (bfr->type == id_BFR && bfr->getPort(id_O)->users.empty()) {
|
||||
@ -1109,6 +1092,19 @@ static int memory_addr_bits(int config,bool ecc)
|
||||
}
|
||||
}
|
||||
|
||||
void NgUltraPacker::insert_wfb(CellInfo *cell, IdString port)
|
||||
{
|
||||
NetInfo *net = cell->getPort(port);
|
||||
if (net) {
|
||||
CellInfo *wfb = create_cell_ptr(id_WFB, ctx->id(std::string(cell->name.c_str(ctx)) + "$" + port.c_str(ctx)));
|
||||
cell->disconnectPort(port);
|
||||
wfb->connectPort(id_ZO, net);
|
||||
NetInfo *new_out = ctx->createNet(ctx->id(net->name.str(ctx) + "$" + port.c_str(ctx)));
|
||||
cell->connectPort(port, new_out);
|
||||
wfb->connectPort(id_ZI, new_out);
|
||||
}
|
||||
}
|
||||
|
||||
void NgUltraPacker::pack_plls(void)
|
||||
{
|
||||
log_info("Packing PLLs..\n");
|
||||
@ -1128,6 +1124,17 @@ void NgUltraPacker::pack_plls(void)
|
||||
disconnect_if_gnd(&ci, id_EXT_CAL5);
|
||||
disconnect_if_gnd(&ci, id_EXT_CAL_LOCKED);
|
||||
disconnect_if_gnd(&ci, id_ARST_CAL);
|
||||
insert_wfb(&ci, id_VCO);
|
||||
insert_wfb(&ci, id_REFO);
|
||||
insert_wfb(&ci, id_LDFO);
|
||||
insert_wfb(&ci, id_CLK_DIV1);
|
||||
insert_wfb(&ci, id_CLK_DIV2);
|
||||
insert_wfb(&ci, id_CLK_DIV3);
|
||||
insert_wfb(&ci, id_CLK_DIVD1);
|
||||
insert_wfb(&ci, id_CLK_DIVD2);
|
||||
insert_wfb(&ci, id_CLK_DIVD3);
|
||||
insert_wfb(&ci, id_CLK_DIVD4);
|
||||
insert_wfb(&ci, id_CLK_DIVD5);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1284,11 +1291,11 @@ void NgUltraPacker::setup()
|
||||
|
||||
// clock_sinks[id_DSP].insert(id_CK);
|
||||
|
||||
// clock_sinks[id_PLL].insert(id_CLK_CAL);
|
||||
// clock_sinks[id_PLL].insert(id_FBK);
|
||||
// clock_sinks[id_PLL].insert(id_REF);
|
||||
// clock_sinks[id_GCK].insert(id_SI1);
|
||||
// clock_sinks[id_GCK].insert(id_SI2);
|
||||
clock_sinks[id_PLL].insert(id_CLK_CAL);
|
||||
clock_sinks[id_PLL].insert(id_FBK);
|
||||
clock_sinks[id_PLL].insert(id_REF);
|
||||
clock_sinks[id_GCK].insert(id_SI1);
|
||||
clock_sinks[id_GCK].insert(id_SI2);
|
||||
|
||||
// clock_sinks[id_IOM].insert(id_ALCK1);
|
||||
// clock_sinks[id_IOM].insert(id_ALCK2);
|
||||
@ -1312,6 +1319,8 @@ void NgUltraPacker::setup()
|
||||
// clock_sinks[id_PMA].insert(id_hssl_clock_i2);
|
||||
// clock_sinks[id_PMA].insert(id_hssl_clock_i3);
|
||||
// clock_sinks[id_PMA].insert(id_hssl_clock_i4);
|
||||
clock_sinks[id_WFB].insert(id_ZI);
|
||||
clock_sinks[id_WFG].insert(id_ZI);
|
||||
}
|
||||
|
||||
void NgUltraImpl::pack()
|
||||
@ -1335,7 +1344,7 @@ void NgUltraImpl::pack()
|
||||
packer.pack_cys();
|
||||
packer.pack_lut_dffs();
|
||||
packer.pack_dffs();
|
||||
packer.promote_globals();
|
||||
packer.insert_ioms();
|
||||
}
|
||||
|
||||
|
||||
@ -1376,28 +1385,32 @@ void NgUltraImpl::postPlace()
|
||||
|
||||
void NgUltraImpl::route_clocks()
|
||||
{
|
||||
log_info("Routing global clocks...\n");
|
||||
dict<IdString,pool<IdString>> glb_sources;
|
||||
glb_sources[id_IOM].insert(id_CKO1);
|
||||
glb_sources[id_IOM].insert(id_CKO2);
|
||||
glb_sources[id_WFB].insert(id_ZO);
|
||||
glb_sources[id_WFG].insert(id_ZO);
|
||||
glb_sources[id_GCK].insert(id_SO);
|
||||
|
||||
log_info("Routing global nets...\n");
|
||||
for (auto &net : ctx->nets) {
|
||||
NetInfo *clk_net = net.second.get();
|
||||
if (!clk_net->driver.cell)
|
||||
NetInfo *glb_net = net.second.get();
|
||||
if (!glb_net->driver.cell)
|
||||
continue;
|
||||
|
||||
// check if we have a global clock net, skip otherwise
|
||||
bool is_global = false;
|
||||
if (clk_net->driver.cell->type.in(id_IOM) && clk_net->driver.port.in(id_CKO1, id_CKO2))
|
||||
is_global = true;
|
||||
if (!is_global)
|
||||
if (!(glb_sources.count(glb_net->driver.cell->type) && glb_sources[glb_net->driver.cell->type].count(glb_net->driver.port)))
|
||||
continue;
|
||||
|
||||
log_info(" routing clock '%s'\n", clk_net->name.c_str(ctx));
|
||||
ctx->bindWire(ctx->getNetinfoSourceWire(clk_net), clk_net, STRENGTH_LOCKED);
|
||||
log_info(" routing net '%s'\n", glb_net->name.c_str(ctx));
|
||||
ctx->bindWire(ctx->getNetinfoSourceWire(glb_net), glb_net, STRENGTH_LOCKED);
|
||||
|
||||
for (auto &usr : clk_net->users) {
|
||||
for (auto &usr : glb_net->users) {
|
||||
std::queue<WireId> visit;
|
||||
dict<WireId, PipId> backtrace;
|
||||
WireId dest = WireId();
|
||||
|
||||
auto sink_wire = ctx->getNetinfoSinkWire(clk_net, usr, 0);
|
||||
auto sink_wire = ctx->getNetinfoSinkWire(glb_net, usr, 0);
|
||||
if (ctx->debug) {
|
||||
auto sink_wire_name = "(uninitialized)";
|
||||
if (sink_wire != WireId())
|
||||
@ -1409,7 +1422,7 @@ void NgUltraImpl::route_clocks()
|
||||
while (!visit.empty()) {
|
||||
WireId curr = visit.front();
|
||||
visit.pop();
|
||||
if (ctx->getBoundWireNet(curr) == clk_net) {
|
||||
if (ctx->getBoundWireNet(curr) == glb_net) {
|
||||
dest = curr;
|
||||
break;
|
||||
}
|
||||
@ -1419,7 +1432,7 @@ void NgUltraImpl::route_clocks()
|
||||
WireId src = ctx->getPipSrcWire(uh);
|
||||
if (backtrace.count(src))
|
||||
continue;
|
||||
if (!ctx->checkWireAvail(src) && ctx->getBoundWireNet(src) != clk_net)
|
||||
if (!ctx->checkWireAvail(src) && ctx->getBoundWireNet(src) != glb_net)
|
||||
continue;
|
||||
backtrace[src] = uh;
|
||||
visit.push(src);
|
||||
@ -1431,13 +1444,13 @@ void NgUltraImpl::route_clocks()
|
||||
while (backtrace.count(dest)) {
|
||||
auto uh = backtrace[dest];
|
||||
dest = ctx->getPipDstWire(uh);
|
||||
if (ctx->getBoundWireNet(dest) == clk_net) {
|
||||
NPNR_ASSERT(clk_net->wires.at(dest).pip == uh);
|
||||
if (ctx->getBoundWireNet(dest) == glb_net) {
|
||||
NPNR_ASSERT(glb_net->wires.at(dest).pip == uh);
|
||||
break;
|
||||
}
|
||||
if (ctx->debug)
|
||||
log_info(" bind pip %s --> %s\n", ctx->nameOfPip(uh), ctx->nameOfWire(dest));
|
||||
ctx->bindPip(uh, clk_net, STRENGTH_LOCKED);
|
||||
ctx->bindPip(uh, glb_net, STRENGTH_LOCKED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -60,7 +60,7 @@ struct NgUltraPacker
|
||||
void pack_plls();
|
||||
void pack_wfgs();
|
||||
|
||||
void promote_globals();
|
||||
void insert_ioms();
|
||||
|
||||
void setup();
|
||||
|
||||
@ -77,6 +77,8 @@ private:
|
||||
void connect_gnd_if_unconnected(CellInfo *cell, IdString input, bool warn);
|
||||
void disconnect_if_gnd(CellInfo *cell, IdString input);
|
||||
|
||||
void insert_wfb(CellInfo *cell, IdString port);
|
||||
|
||||
void mandatory_param(CellInfo *cell, IdString param);
|
||||
void disconnect_unused(CellInfo *cell, IdString port);
|
||||
// General helper functions
|
||||
|
Loading…
Reference in New Issue
Block a user