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)
{
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)

View File

@ -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);

View File

@ -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));
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_io_wire, &ctx->net_info(net.name), STRENGTH_LOCKED);
ctx->bindWire(net.clock_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;
}
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_io_bel);
}
BelInfo &bi = ctx->bel_info(net.clock_bel);
bi.gb = true;
nets.emplace_back(net);
}

View File

@ -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
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);

View File

@ -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-auto-longwires")] = 0;
if (vm.count("enable-globals")) {
ctx->settings[ctx->id("arch.enable-globals")] = 1;
ctx->settings[ctx->id("arch.enable-auto-longwires")] = 0;
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;