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