diff options
author | YRabbit <rabbit@yrabbit.cyou> | 2022-12-30 11:55:39 +1000 |
---|---|---|
committer | YRabbit <rabbit@yrabbit.cyou> | 2022-12-30 11:55:39 +1000 |
commit | b8ab3116b223648af19c190c392c1fe36844907b (patch) | |
tree | 6226d4a8605d8b99ff1e629d4d9dae0eb6b9e7c0 /gowin/globals.cc | |
parent | 8424dc79d2555ce6b070371c9a5fb11aa76e950d (diff) | |
download | nextpnr-b8ab3116b223648af19c190c392c1fe36844907b.tar.gz nextpnr-b8ab3116b223648af19c190c392c1fe36844907b.tar.bz2 nextpnr-b8ab3116b223648af19c190c392c1fe36844907b.zip |
gowin: improve clock wire routing
The dedicated router for clock wires now understands not only the IO
pins but also the rPLL outputs as clock sources.
This simple router sets an optimal route, so it is now the default
router. It can be disabled with the --disable-globals command line flag
if desired, but this is not recommended due to possible clock skew.
Still for GW1N-4C there is no good router for clock wires as there
external quartz resonator is connected via PLL.
Signed-off-by: YRabbit <rabbit@yrabbit.cyou>
Diffstat (limited to 'gowin/globals.cc')
-rw-r--r-- | gowin/globals.cc | 73 |
1 files changed, 43 insertions, 30 deletions
diff --git a/gowin/globals.cc b/gowin/globals.cc index 21ee722a..785a0111 100644 --- a/gowin/globals.cc +++ b/gowin/globals.cc @@ -38,22 +38,28 @@ bool GowinGlobalRouter::is_clock_port(PortRef const &user) return false; } -std::pair<WireId, BelId> GowinGlobalRouter::clock_io(Context *ctx, PortRef const &driver) +std::pair<WireId, BelId> GowinGlobalRouter::clock_src(Context *ctx, PortRef const &driver) { - // XXX normally all alternative functions of the pins should be passed - // in the chip database, but at the moment we find them from aliases/pips - // XXX check diff inputs too - if (driver.cell == nullptr || driver.cell->type != id_IOB || !driver.cell->attrs.count(id_BEL)) { + if (driver.cell == nullptr) { return std::make_pair(WireId(), BelId()); } - // clock IOs have pips output->SPINExx - BelInfo &bel = ctx->bel_info(ctx->id(driver.cell->attrs[id_BEL].as_string())); - WireId wire = bel.pins[id_O].wire; - for (auto const pip : ctx->getPipsDownhill(wire)) { - if (ctx->wire_info(ctx->getPipDstWire(pip)).type.str(ctx).rfind("SPINE", 0) == 0) { + BelInfo &bel = ctx->bel_info(driver.cell->bel); + WireId wire; + if (driver.cell->type == id_IOB) { + if (ctx->is_GCLKT_iob(driver.cell)) { + wire = bel.pins[id_O].wire; return std::make_pair(wire, bel.name); } + return std::make_pair(WireId(), BelId()); + } + if (driver.cell->type == id_RPLLA) { + if (driver.port == id_CLKOUT || driver.port == id_CLKOUTP || driver.port == id_CLKOUTD || + driver.port == id_CLKOUTD3) { + wire = bel.pins[driver.port].wire; + return std::make_pair(wire, bel.name); + } + return std::make_pair(WireId(), BelId()); } return std::make_pair(WireId(), BelId()); } @@ -64,12 +70,12 @@ void GowinGlobalRouter::gather_clock_nets(Context *ctx, std::vector<globalnet_t> for (auto const &net : ctx->nets) { NetInfo const *ni = net.second.get(); auto new_clock = clock_nets.end(); - auto clock_wire_bel = clock_io(ctx, ni->driver); + auto clock_wire_bel = clock_src(ctx, ni->driver); if (clock_wire_bel.first != WireId()) { clock_nets.emplace_back(net.first); new_clock = --clock_nets.end(); - new_clock->clock_io_wire = clock_wire_bel.first; - new_clock->clock_io_bel = clock_wire_bel.second; + new_clock->clock_wire = clock_wire_bel.first; + new_clock->clock_bel = clock_wire_bel.second; } for (auto const &user : ni->users) { if (is_clock_port(user)) { @@ -86,8 +92,8 @@ void GowinGlobalRouter::gather_clock_nets(Context *ctx, std::vector<globalnet_t> if (ctx->verbose) { for (auto const &net : clock_nets) { - log_info(" Net:%s, ports:%d, io:%s\n", net.name.c_str(ctx), net.clock_ports, - net.clock_io_wire == WireId() ? "No" : net.clock_io_wire.c_str(ctx)); + log_info(" Net:%s, ports:%d, clock source:%s\n", net.name.c_str(ctx), net.clock_ports, + net.clock_wire == WireId() ? "No" : net.clock_wire.c_str(ctx)); } } } @@ -238,33 +244,35 @@ void GowinGlobalRouter::route_net(Context *ctx, globalnet_t const &net) } used_pips.insert(spine_pip_id); - // >>> SPINExx <- IO + // >>> SPINExx <- Src dstWire = ctx->getPipSrcWire(spine_pip_id); dstWireInfo = ctx->wire_info(dstWire); - PipId io_pip_id = PipId(); + PipId src_pip_id = PipId(); for (auto const uphill_pip : ctx->getPipsUphill(dstWire)) { - if (ctx->getPipSrcWire(uphill_pip) == net.clock_io_wire) { - io_pip_id = uphill_pip; + if (ctx->getPipSrcWire(uphill_pip) == net.clock_wire) { + src_pip_id = uphill_pip; } } - NPNR_ASSERT(io_pip_id != PipId()); + NPNR_ASSERT(src_pip_id != PipId()); if (ctx->verbose) { - log_info(" IO Pip:%s\n", io_pip_id.c_str(ctx)); + log_info(" Src Pip:%s\n", src_pip_id.c_str(ctx)); } // if already routed - if (used_pips.count(io_pip_id)) { + if (used_pips.count(src_pip_id)) { if (ctx->verbose) { log_info(" ^routed already^\n"); } continue; } - used_pips.insert(io_pip_id); + used_pips.insert(src_pip_id); } log_info(" Net %s is routed.\n", net.name.c_str(ctx)); - for (auto const pip : used_pips) { - ctx->bindPip(pip, &ctx->net_info(net.name), STRENGTH_LOCKED); + if (!ctx->net_info(net.name).users.empty()) { + for (auto const pip : used_pips) { + ctx->bindPip(pip, &ctx->net_info(net.name), STRENGTH_LOCKED); + } + ctx->bindWire(net.clock_wire, &ctx->net_info(net.name), STRENGTH_LOCKED); } - ctx->bindWire(net.clock_io_wire, &ctx->net_info(net.name), STRENGTH_LOCKED); } void GowinGlobalRouter::route_globals(Context *ctx) @@ -289,16 +297,21 @@ void GowinGlobalRouter::mark_globals(Context *ctx) int max_clock = 3, cur_clock = -1; for (auto &net : clock_nets) { // XXX only IO clock for now - if (net.clock_io_wire == WireId()) { - log_info(" Non IO clock, skip %s.\n", net.name.c_str(ctx)); + if (net.clock_wire == WireId()) { + log_info(" Non clock source, skip %s.\n", net.name.c_str(ctx)); continue; } if (++cur_clock >= max_clock) { log_info(" No more clock wires left, skip the remaining nets.\n"); break; } - net.clock = cur_clock; - BelInfo &bi = ctx->bel_info(net.clock_io_bel); + if (ctx->net_info(net.name).users.empty()) { + --cur_clock; + net.clock = -1; + } else { + net.clock = cur_clock; + } + BelInfo &bi = ctx->bel_info(net.clock_bel); bi.gb = true; nets.emplace_back(net); } |