diff options
author | myrtle <gatecat@ds0.me> | 2022-12-06 21:20:59 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-12-06 21:20:59 +0100 |
commit | a342b96bb0d4370d3e575a0189da2273b94ea765 (patch) | |
tree | 5f0ea98677a3e7ed64fde977c4297114219b53fc | |
parent | cd3b76e3f7ce9d9927087f6fdd38e04968688ee7 (diff) | |
parent | 150a482b77877bac6943d8554cd6283837bf7308 (diff) | |
download | nextpnr-a342b96bb0d4370d3e575a0189da2273b94ea765.tar.gz nextpnr-a342b96bb0d4370d3e575a0189da2273b94ea765.tar.bz2 nextpnr-a342b96bb0d4370d3e575a0189da2273b94ea765.zip |
Merge pull request #1055 from yrabbit/pll-pins
gowin: add PLL pins processing
-rw-r--r-- | gowin/arch.cc | 136 | ||||
-rw-r--r-- | gowin/arch.h | 4 | ||||
-rw-r--r-- | gowin/cells.h | 2 | ||||
-rw-r--r-- | gowin/constids.inc | 3 | ||||
-rw-r--r-- | gowin/pack.cc | 11 |
5 files changed, 140 insertions, 16 deletions
diff --git a/gowin/arch.cc b/gowin/arch.cc index 756580e0..4d732680 100644 --- a/gowin/arch.cc +++ b/gowin/arch.cc @@ -23,6 +23,7 @@ #include <iostream> #include <math.h> #include <regex> +#include "design_utils.h" #include "embed.h" #include "gfx.h" #include "nextpnr.h" @@ -1575,6 +1576,24 @@ Arch::Arch(ArchArgs args) : args(args) } } } + + // IO pin configs + for (unsigned int i = 0; i < package->num_pins; i++) { + const PinPOD *pin = &package->pins[i]; + if (pin->num_cfgs == 0) { + continue; + } + auto b = bels.find(IdString(pin->loc_id)); + if (b == bels.end()) { + // Not all pins are transmitted, e.g. MODE, DONE etc. + continue; + } + std::vector<IdString> &cfgs = b->second.pin_cfgs; + for (unsigned int j = 0; j < pin->num_cfgs; ++j) { + cfgs.push_back(IdString(pin->cfgs[j])); + } + } + // setup pips for (int i = 0; i < db->rows * db->cols; i++) { int row = i / db->cols; @@ -1958,26 +1977,128 @@ bool Arch::place() return retVal; } +static bool is_spec_iob(const Context *ctx, const CellInfo *cell, IdString pin_name) +{ + if (!is_iob(ctx, cell)) { + return false; + } + std::vector<IdString> const &cfgs = ctx->bels.at(cell->bel).pin_cfgs; + bool have_pin = std::find(cfgs.begin(), cfgs.end(), pin_name) != cfgs.end(); + return have_pin; +} + +static bool is_PLL_T_IN_iob(const Context *ctx, const CellInfo *cell) +{ + return is_spec_iob(ctx, cell, ctx->id("RPLL_T_IN")); +} + +static bool is_PLL_T_FB_iob(const Context *ctx, const CellInfo *cell) +{ + return is_spec_iob(ctx, cell, ctx->id("RPLL_T_FB")); +} + +// If the PLL input can be connected using a direct wire, then do so, +// bypassing conventional routing. +void Arch::fix_pll_nets(Context *ctx) +{ + for (auto &cell : ctx->cells) { + CellInfo *ci = cell.second.get(); + if (ci->type != id_RPLLA) { + continue; + } + // *** CLKIN + do { + if (!port_used(ci, id_CLKIN)) { + ci->setParam(id_INSEL, Property("UNKNOWN")); + break; + } + NetInfo *net = ci->getPort(id_CLKIN); + if (net->name == id("$PACKER_VCC_NET") || net->name == id("$PACKER_GND_NET")) { + ci->setParam(id_INSEL, Property("UNKNOWN")); + break; + } + if (net_driven_by(ctx, net, is_PLL_T_IN_iob, id_O) != nullptr) { + ci->disconnectPort(id_CLKIN); + ci->setParam(id_INSEL, Property("CLKIN0")); + break; + } + // XXX do special bels (HCLK etc) + // This is general routing through CLK0 pip + ci->setParam(id_INSEL, Property("CLKIN1")); + } while (0); + + do { + // *** CLKFB + if (str_or_default(ci->params, id_CLKFB_SEL, "internal") == "internal") { + ci->setParam(id_FBSEL, Property("CLKFB3")); + continue; + } + if (!port_used(ci, id_CLKFB)) { + ci->setParam(id_FBSEL, Property("UNKNOWN")); + continue; + } + NetInfo *net = ci->getPort(id_CLKFB); + if (net->name == id("$PACKER_VCC_NET") || net->name == id("$PACKER_GND_NET")) { + ci->setParam(id_FBSEL, Property("UNKNOWN")); + continue; + } + if (net_driven_by(ctx, net, is_PLL_T_FB_iob, id_O) != nullptr) { + ci->disconnectPort(id_CLKFB); + ci->setParam(id_FBSEL, Property("CLKFB2")); + break; + } + // XXX do special bels (HCLK etc) + // This is general routing through CLK2 pip + ci->setParam(id_FBSEL, Property("CLKFB0")); + } while (0); + + // resets + Property pr_enable("ENABLE"), pr_disable("DISABLE"); + NetInfo *net = ci->getPort(id_RESET); + ci->setParam(id_RSTEN, pr_enable); + if (!port_used(ci, id_RESET) || net->name == id("$PACKER_VCC_NET") || net->name == id("$PACKER_GND_NET")) { + ci->setParam(id_RSTEN, pr_disable); + } + ci->setParam(id_PWDEN, pr_enable); + net = ci->getPort(id_RESET_P); + if (!port_used(ci, id_RESET_P) || net->name == id("$PACKER_VCC_NET") || net->name == id("$PACKER_GND_NET")) { + ci->setParam(id_PWDEN, pr_disable); + } + } +} + +void Arch::pre_route(Context *ctx) +{ + fix_pll_nets(ctx); + if (bool_or_default(settings, id("arch.enable-globals"))) { + mark_gowin_globals(ctx); + } +} + +void Arch::post_route(Context *ctx) { fix_longwire_bels(); } + bool Arch::route() { std::string router = str_or_default(settings, id_router, defaultRouter); + Context *ctx = getCtx(); + pre_route(ctx); if (bool_or_default(settings, id("arch.enable-globals"))) { - route_gowin_globals(getCtx()); + route_gowin_globals(ctx); } bool result; if (router == "router1") { - result = router1(getCtx(), Router1Cfg(getCtx())); + result = router1(ctx, Router1Cfg(ctx)); } else if (router == "router2") { - router2(getCtx(), Router2Cfg(getCtx())); + router2(ctx, Router2Cfg(ctx)); result = true; } else { log_error("Gowin architecture does not support router '%s'\n", router.c_str()); } getCtx()->settings[id_route] = 1; archInfoToAttributes(); - fix_longwire_bels(); + post_route(ctx); return result; } @@ -2174,11 +2295,6 @@ void Arch::pre_pack(Context *ctx) } } -void Arch::post_pack(Context *ctx) -{ - if (bool_or_default(settings, id("arch.enable-globals"))) { - mark_gowin_globals(ctx); - } -} +void Arch::post_pack(Context *ctx) {} NEXTPNR_NAMESPACE_END diff --git a/gowin/arch.h b/gowin/arch.h index 0591e41a..3e614eba 100644 --- a/gowin/arch.h +++ b/gowin/arch.h @@ -227,6 +227,7 @@ struct BelInfo std::map<IdString, std::string> attrs; CellInfo *bound_cell; dict<IdString, PinInfo> pins; + std::vector<IdString> pin_cfgs; DecalXY decalxy_active, decalxy_inactive; int x, y, z; bool gb; @@ -474,8 +475,11 @@ struct Arch : BaseArch<ArchRanges> void fix_longwire_bels(); void pre_pack(Context *ctx); void post_pack(Context *ctx); + void pre_route(Context *ctx); + void post_route(Context *ctx); void auto_longwires(); void add_plla_ports(BelsPOD const *bel, IdString belname, int row, int col); + void fix_pll_nets(Context *ctx); GowinGlobalRouter globals_router; void mark_gowin_globals(Context *ctx); diff --git a/gowin/cells.h b/gowin/cells.h index 227206c8..ae475b77 100644 --- a/gowin/cells.h +++ b/gowin/cells.h @@ -105,6 +105,8 @@ inline bool is_lc(const BaseCtx *ctx, const CellInfo *cell) { return cell->type inline bool is_sram(const BaseCtx *ctx, const CellInfo *cell) { return cell->type == id_RAM16SDP4; } +inline bool is_iob(const Context *ctx, const CellInfo *cell) { return (cell->type.index == ID_IOB); } + // Convert a LUT primitive to (part of) an GENERIC_SLICE, swapping ports // as needed. Set no_dff if a DFF is not being used, so that the output // can be reconnected diff --git a/gowin/constids.inc b/gowin/constids.inc index e0b37b49..610755bb 100644 --- a/gowin/constids.inc +++ b/gowin/constids.inc @@ -938,6 +938,9 @@ X(CLKOUTDIV3) X(PWDEN) X(RSTEN) X(FLOCK) +X(INSEL) +X(FBSEL) +X(CLKFB_SEL) // timing X(X0) diff --git a/gowin/pack.cc b/gowin/pack.cc index 1e0380c1..c36a4757 100644 --- a/gowin/pack.cc +++ b/gowin/pack.cc @@ -820,8 +820,6 @@ static bool is_gowin_iologic(const Context *ctx, const CellInfo *cell) } } -static bool is_iob(const Context *ctx, const CellInfo *cell) { return (cell->type.index == ID_IOB); } - // Pack IO logic static void pack_iologic(Context *ctx) { @@ -1021,10 +1019,11 @@ static void pack_plls(Context *ctx) if (parm_device == "GW1N-1" || parm_device == "GW1NZ-1") { // Unused ports will be disabled during image generation. Here we add flags for such ports. Property pr_enable("ENABLE"), pr_disable("DISABLE"); - IdString ports[][2] = {{id_CLKOUTP, id_CLKOUTPS}, {id_CLKOUTD, id_CLKOUTDIV}, - {id_CLKOUTD3, id_CLKOUTDIV3}, {id_LOCK, id_FLOCK}, - {id_RESET_P, id_PWDEN}, {id_RESET, id_RSTEN}}; - for (int i = 0; i < 6; ++i) { + IdString ports[][2] = {{id_CLKOUTP, id_CLKOUTPS}, + {id_CLKOUTD, id_CLKOUTDIV}, + {id_CLKOUTD3, id_CLKOUTDIV3}, + {id_LOCK, id_FLOCK}}; + for (int i = 0; i < 4; ++i) { ci->setParam(ports[i][1], port_used(ci, ports[i][0]) ? pr_enable : pr_disable); } // B half |