diff options
author | YRabbit <rabbit@yrabbit.cyou> | 2022-12-04 15:06:44 +1000 |
---|---|---|
committer | YRabbit <rabbit@yrabbit.cyou> | 2022-12-04 15:06:44 +1000 |
commit | 2e68962a025999ec85276f6362540c13ccfcd752 (patch) | |
tree | e1c0d9538a33bce405a5d14ca67baa6ccd1297b9 | |
parent | f07d9a18356ec8df74d9c42693f7b9307e390a7f (diff) | |
download | nextpnr-2e68962a025999ec85276f6362540c13ccfcd752.tar.gz nextpnr-2e68962a025999ec85276f6362540c13ccfcd752.tar.bz2 nextpnr-2e68962a025999ec85276f6362540c13ccfcd752.zip |
gowin: add PLL pins processing
Uses the information of the special input pins for the PLL in the
current chip. If such pins are involved, no routing is performed and
information about the use of implicit wires is passed to the packer.
The RESET and RESET_P inputs are now also disabled if they are connected
to VSS/VCC.
Signed-off-by: YRabbit <rabbit@yrabbit.cyou>
-rw-r--r-- | gowin/arch.cc | 123 | ||||
-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, 133 insertions, 10 deletions
diff --git a/gowin/arch.cc b/gowin/arch.cc index 756580e0..ccfe2c4b 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,122 @@ 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); } + +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; } 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 |