Merge pull request #1071 from yrabbit/to-float

gowin: bugfix and improved clock router
This commit is contained in:
myrtle 2022-12-30 11:58:39 +01:00 committed by GitHub
commit eaf2bc8bdd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 85 additions and 50 deletions

View File

@ -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) DelayQuad delayLookup(const TimingPOD *first, int len, IdString name)
{ {
TimingPOD needle; TimingPOD needle;
needle.name_id = name.index; needle.name_id = name.index;
const TimingPOD *timing = genericLookup(first, len, needle, timingCompare); const TimingPOD *timing = timingLookup(first, len, needle, timingCompare);
DelayQuad delay; DelayQuad delay;
if (timing != nullptr) { if (timing != nullptr) {
delay.fall.max_delay = std::max(timing->ff, timing->rf) / 1000; delay.fall.max_delay = std::max(timing->ff, timing->rf) / 1000.;
delay.fall.min_delay = std::min(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.max_delay = std::max(timing->rr, timing->fr) / 1000.;
delay.rise.min_delay = std::min(timing->rr, timing->fr) / 1000; delay.rise.min_delay = std::min(timing->rr, timing->fr) / 1000.;
} else { } else {
delay = DelayQuad(0); 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")); 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, // If the PLL input can be connected using a direct wire, then do so,
// bypassing conventional routing. // bypassing conventional routing.
void Arch::fix_pll_nets(Context *ctx) void Arch::fix_pll_nets(Context *ctx)

View File

@ -480,6 +480,7 @@ struct Arch : BaseArch<ArchRanges>
void auto_longwires(); void auto_longwires();
void add_plla_ports(BelsPOD const *bel, IdString belname, int row, int col); void add_plla_ports(BelsPOD const *bel, IdString belname, int row, int col);
void fix_pll_nets(Context *ctx); void fix_pll_nets(Context *ctx);
bool is_GCLKT_iob(const CellInfo *cell);
GowinGlobalRouter globals_router; GowinGlobalRouter globals_router;
void mark_gowin_globals(Context *ctx); void mark_gowin_globals(Context *ctx);

View File

@ -38,22 +38,28 @@ bool GowinGlobalRouter::is_clock_port(PortRef const &user)
return false; 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 if (driver.cell == nullptr) {
// 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)) {
return std::make_pair(WireId(), BelId()); 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())); BelInfo &bel = ctx->bel_info(driver.cell->bel);
WireId wire = bel.pins[id_O].wire; WireId wire;
for (auto const pip : ctx->getPipsDownhill(wire)) { if (driver.cell->type == id_IOB) {
if (ctx->wire_info(ctx->getPipDstWire(pip)).type.str(ctx).rfind("SPINE", 0) == 0) { if (ctx->is_GCLKT_iob(driver.cell)) {
wire = bel.pins[id_O].wire;
return std::make_pair(wire, bel.name); 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()); 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) { for (auto const &net : ctx->nets) {
NetInfo const *ni = net.second.get(); NetInfo const *ni = net.second.get();
auto new_clock = clock_nets.end(); 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()) { if (clock_wire_bel.first != WireId()) {
clock_nets.emplace_back(net.first); clock_nets.emplace_back(net.first);
new_clock = --clock_nets.end(); new_clock = --clock_nets.end();
new_clock->clock_io_wire = clock_wire_bel.first; new_clock->clock_wire = clock_wire_bel.first;
new_clock->clock_io_bel = clock_wire_bel.second; new_clock->clock_bel = clock_wire_bel.second;
} }
for (auto const &user : ni->users) { for (auto const &user : ni->users) {
if (is_clock_port(user)) { if (is_clock_port(user)) {
@ -86,8 +92,8 @@ void GowinGlobalRouter::gather_clock_nets(Context *ctx, std::vector<globalnet_t>
if (ctx->verbose) { if (ctx->verbose) {
for (auto const &net : clock_nets) { for (auto const &net : clock_nets) {
log_info(" Net:%s, ports:%d, io:%s\n", net.name.c_str(ctx), net.clock_ports, log_info(" Net:%s, ports:%d, clock source:%s\n", net.name.c_str(ctx), net.clock_ports,
net.clock_io_wire == WireId() ? "No" : net.clock_io_wire.c_str(ctx)); 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); used_pips.insert(spine_pip_id);
// >>> SPINExx <- IO // >>> SPINExx <- Src
dstWire = ctx->getPipSrcWire(spine_pip_id); dstWire = ctx->getPipSrcWire(spine_pip_id);
dstWireInfo = ctx->wire_info(dstWire); dstWireInfo = ctx->wire_info(dstWire);
PipId io_pip_id = PipId(); PipId src_pip_id = PipId();
for (auto const uphill_pip : ctx->getPipsUphill(dstWire)) { for (auto const uphill_pip : ctx->getPipsUphill(dstWire)) {
if (ctx->getPipSrcWire(uphill_pip) == net.clock_io_wire) { if (ctx->getPipSrcWire(uphill_pip) == net.clock_wire) {
io_pip_id = uphill_pip; src_pip_id = uphill_pip;
} }
} }
NPNR_ASSERT(io_pip_id != PipId()); NPNR_ASSERT(src_pip_id != PipId());
if (ctx->verbose) { 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 already routed
if (used_pips.count(io_pip_id)) { if (used_pips.count(src_pip_id)) {
if (ctx->verbose) { if (ctx->verbose) {
log_info(" ^routed already^\n"); log_info(" ^routed already^\n");
} }
continue; 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)); log_info(" Net %s is routed.\n", net.name.c_str(ctx));
for (auto const pip : used_pips) { if (!ctx->net_info(net.name).users.empty()) {
ctx->bindPip(pip, &ctx->net_info(net.name), STRENGTH_LOCKED); 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) void GowinGlobalRouter::route_globals(Context *ctx)
@ -289,16 +297,21 @@ void GowinGlobalRouter::mark_globals(Context *ctx)
int max_clock = 3, cur_clock = -1; int max_clock = 3, cur_clock = -1;
for (auto &net : clock_nets) { for (auto &net : clock_nets) {
// XXX only IO clock for now // XXX only IO clock for now
if (net.clock_io_wire == WireId()) { if (net.clock_wire == WireId()) {
log_info(" Non IO clock, skip %s.\n", net.name.c_str(ctx)); log_info(" Non clock source, skip %s.\n", net.name.c_str(ctx));
continue; continue;
} }
if (++cur_clock >= max_clock) { if (++cur_clock >= max_clock) {
log_info(" No more clock wires left, skip the remaining nets.\n"); log_info(" No more clock wires left, skip the remaining nets.\n");
break; break;
} }
net.clock = cur_clock; if (ctx->net_info(net.name).users.empty()) {
BelInfo &bi = ctx->bel_info(net.clock_io_bel); --cur_clock;
net.clock = -1;
} else {
net.clock = cur_clock;
}
BelInfo &bi = ctx->bel_info(net.clock_bel);
bi.gb = true; bi.gb = true;
nets.emplace_back(net); nets.emplace_back(net);
} }

View File

@ -39,32 +39,32 @@ class GowinGlobalRouter
{ {
IdString name; IdString name;
int clock_ports; int clock_ports;
BelId clock_io_bel; BelId clock_bel;
WireId clock_io_wire; // IO wire if there is one WireId clock_wire; // clock wire if there is one
int clock; // clock # int clock; // clock #
globalnet_t() globalnet_t()
{ {
name = IdString(); name = IdString();
clock_ports = 0; clock_ports = 0;
clock_io_bel = BelId(); clock_bel = BelId();
clock_io_wire = WireId(); clock_wire = WireId();
clock = -1; clock = -1;
} }
globalnet_t(IdString _name) globalnet_t(IdString _name)
{ {
name = _name; name = _name;
clock_ports = 0; clock_ports = 0;
clock_io_bel = BelId(); clock_bel = BelId();
clock_io_wire = WireId(); clock_wire = WireId();
clock = -1; clock = -1;
} }
// sort // sort
bool operator<(const globalnet_t &other) const bool operator<(const globalnet_t &other) const
{ {
if ((clock_io_wire != WireId()) ^ (other.clock_io_wire != WireId())) { if ((clock_wire != WireId()) ^ (other.clock_wire != WireId())) {
return !(clock_io_wire != WireId()); return !(clock_wire != WireId());
} }
return clock_ports < other.clock_ports; return clock_ports < other.clock_ports;
} }
@ -76,7 +76,7 @@ class GowinGlobalRouter
std::vector<globalnet_t> nets; std::vector<globalnet_t> nets;
bool is_clock_port(PortRef const &user); 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); 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, IdString route_to_non_clock_port(Context *ctx, WireId const dstWire, int clock, pool<IdString> &used_pips,
pool<IdString> &undo_wires); pool<IdString> &undo_wires);

View File

@ -51,7 +51,8 @@ po::options_description GowinCommandHandler::getArchOptions()
specific.add_options()("device", po::value<std::string>(), "device name"); specific.add_options()("device", po::value<std::string>(), "device name");
specific.add_options()("family", po::value<std::string>(), "family 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()("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"); specific.add_options()("enable-auto-longwires", "automatic detection and routing of long wires");
return specific; 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)); auto ctx = std::unique_ptr<Context>(new Context(chipArgs));
// routing options // routing options
// the default values will change in the future ctx->settings[ctx->id("arch.enable-globals")] = 1;
ctx->settings[ctx->id("arch.enable-globals")] = 0;
ctx->settings[ctx->id("arch.enable-auto-longwires")] = 0; ctx->settings[ctx->id("arch.enable-auto-longwires")] = 0;
if (vm.count("enable-globals")) { if (vm.count("disable-globals")) {
ctx->settings[ctx->id("arch.enable-globals")] = 1; ctx->settings[ctx->id("arch.enable-globals")] = 0;
} }
if (vm.count("enable-auto-longwires")) { if (vm.count("enable-auto-longwires")) {
ctx->settings[ctx->id("arch.enable-auto-longwires")] = 1; ctx->settings[ctx->id("arch.enable-auto-longwires")] = 1;