aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormyrtle <gatecat@ds0.me>2022-12-30 11:58:39 +0100
committerGitHub <noreply@github.com>2022-12-30 11:58:39 +0100
commiteaf2bc8bdd185f833b828f118ebe9cd4dc1f7fff (patch)
tree6226d4a8605d8b99ff1e629d4d9dae0eb6b9e7c0
parent0004cd54dbe9278ee5cdc72b044f0d7a7a5cbbf3 (diff)
parentb8ab3116b223648af19c190c392c1fe36844907b (diff)
downloadnextpnr-eaf2bc8bdd185f833b828f118ebe9cd4dc1f7fff.tar.gz
nextpnr-eaf2bc8bdd185f833b828f118ebe9cd4dc1f7fff.tar.bz2
nextpnr-eaf2bc8bdd185f833b828f118ebe9cd4dc1f7fff.zip
Merge pull request #1071 from yrabbit/to-float
gowin: bugfix and improved clock router
-rw-r--r--gowin/arch.cc31
-rw-r--r--gowin/arch.h1
-rw-r--r--gowin/globals.cc73
-rw-r--r--gowin/globals.h20
-rw-r--r--gowin/main.cc10
5 files changed, 85 insertions, 50 deletions
diff --git a/gowin/arch.cc b/gowin/arch.cc
index 8c908b04..33f25405 100644
--- a/gowin/arch.cc
+++ b/gowin/arch.cc
@@ -698,17 +698,28 @@ template <class T, class C> const T *genericLookup(const T *first, int len, cons
}
}
+template <class T, class C> const T *timingLookup(const T *first, int len, const T val, C compare)
+{
+ for (int i = 0; i < len; ++i) {
+ auto res = &first[i];
+ if (!(compare(*res, val) || compare(val, *res))) {
+ return res;
+ }
+ }
+ return nullptr;
+}
+
DelayQuad delayLookup(const TimingPOD *first, int len, IdString name)
{
TimingPOD needle;
needle.name_id = name.index;
- const TimingPOD *timing = genericLookup(first, len, needle, timingCompare);
+ const TimingPOD *timing = timingLookup(first, len, needle, timingCompare);
DelayQuad delay;
if (timing != nullptr) {
- delay.fall.max_delay = std::max(timing->ff, timing->rf) / 1000;
- delay.fall.min_delay = std::min(timing->ff, timing->rf) / 1000;
- delay.rise.max_delay = std::max(timing->rr, timing->fr) / 1000;
- delay.rise.min_delay = std::min(timing->rr, timing->fr) / 1000;
+ delay.fall.max_delay = std::max(timing->ff, timing->rf) / 1000.;
+ delay.fall.min_delay = std::min(timing->ff, timing->rf) / 1000.;
+ delay.rise.max_delay = std::max(timing->rr, timing->fr) / 1000.;
+ delay.rise.min_delay = std::min(timing->rr, timing->fr) / 1000.;
} else {
delay = DelayQuad(0);
}
@@ -2005,6 +2016,16 @@ static bool is_PLL_T_FB_iob(const Context *ctx, const CellInfo *cell)
return is_spec_iob(ctx, cell, ctx->id("RPLL_T_FB"));
}
+bool Arch::is_GCLKT_iob(const CellInfo *cell)
+{
+ for (int i = 0; i < 6; ++i) {
+ if (is_spec_iob(getCtx(), cell, idf("GCLKT_%d", i))) {
+ return true;
+ }
+ }
+ return false;
+}
+
// If the PLL input can be connected using a direct wire, then do so,
// bypassing conventional routing.
void Arch::fix_pll_nets(Context *ctx)
diff --git a/gowin/arch.h b/gowin/arch.h
index bbaf3e60..a5c339cc 100644
--- a/gowin/arch.h
+++ b/gowin/arch.h
@@ -480,6 +480,7 @@ struct Arch : BaseArch<ArchRanges>
void auto_longwires();
void add_plla_ports(BelsPOD const *bel, IdString belname, int row, int col);
void fix_pll_nets(Context *ctx);
+ bool is_GCLKT_iob(const CellInfo *cell);
GowinGlobalRouter globals_router;
void mark_gowin_globals(Context *ctx);
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);
}
diff --git a/gowin/globals.h b/gowin/globals.h
index 69232d7c..307a1a2c 100644
--- a/gowin/globals.h
+++ b/gowin/globals.h
@@ -39,32 +39,32 @@ class GowinGlobalRouter
{
IdString name;
int clock_ports;
- BelId clock_io_bel;
- WireId clock_io_wire; // IO wire if there is one
- int clock; // clock #
+ BelId clock_bel;
+ WireId clock_wire; // clock wire if there is one
+ int clock; // clock #
globalnet_t()
{
name = IdString();
clock_ports = 0;
- clock_io_bel = BelId();
- clock_io_wire = WireId();
+ clock_bel = BelId();
+ clock_wire = WireId();
clock = -1;
}
globalnet_t(IdString _name)
{
name = _name;
clock_ports = 0;
- clock_io_bel = BelId();
- clock_io_wire = WireId();
+ clock_bel = BelId();
+ clock_wire = WireId();
clock = -1;
}
// sort
bool operator<(const globalnet_t &other) const
{
- if ((clock_io_wire != WireId()) ^ (other.clock_io_wire != WireId())) {
- return !(clock_io_wire != WireId());
+ if ((clock_wire != WireId()) ^ (other.clock_wire != WireId())) {
+ return !(clock_wire != WireId());
}
return clock_ports < other.clock_ports;
}
@@ -76,7 +76,7 @@ class GowinGlobalRouter
std::vector<globalnet_t> nets;
bool is_clock_port(PortRef const &user);
- std::pair<WireId, BelId> clock_io(Context *ctx, PortRef const &driver);
+ std::pair<WireId, BelId> clock_src(Context *ctx, PortRef const &driver);
void gather_clock_nets(Context *ctx, std::vector<globalnet_t> &clock_nets);
IdString route_to_non_clock_port(Context *ctx, WireId const dstWire, int clock, pool<IdString> &used_pips,
pool<IdString> &undo_wires);
diff --git a/gowin/main.cc b/gowin/main.cc
index 36bd8656..ccf4d190 100644
--- a/gowin/main.cc
+++ b/gowin/main.cc
@@ -51,7 +51,8 @@ po::options_description GowinCommandHandler::getArchOptions()
specific.add_options()("device", po::value<std::string>(), "device name");
specific.add_options()("family", po::value<std::string>(), "family name");
specific.add_options()("cst", po::value<std::string>(), "physical constraints file");
- specific.add_options()("enable-globals", "separate routing of the clocks");
+ specific.add_options()("enable-globals", "enable separate routing of the clocks");
+ specific.add_options()("disable-globals", "disable separate routing of the clocks");
specific.add_options()("enable-auto-longwires", "automatic detection and routing of long wires");
return specific;
}
@@ -84,11 +85,10 @@ std::unique_ptr<Context> GowinCommandHandler::createContext(dict<std::string, Pr
auto ctx = std::unique_ptr<Context>(new Context(chipArgs));
// routing options
- // the default values will change in the future
- ctx->settings[ctx->id("arch.enable-globals")] = 0;
+ ctx->settings[ctx->id("arch.enable-globals")] = 1;
ctx->settings[ctx->id("arch.enable-auto-longwires")] = 0;
- if (vm.count("enable-globals")) {
- ctx->settings[ctx->id("arch.enable-globals")] = 1;
+ if (vm.count("disable-globals")) {
+ ctx->settings[ctx->id("arch.enable-globals")] = 0;
}
if (vm.count("enable-auto-longwires")) {
ctx->settings[ctx->id("arch.enable-auto-longwires")] = 1;