aboutsummaryrefslogtreecommitdiffstats
path: root/gowin
diff options
context:
space:
mode:
authorYRabbit <rabbit@yrabbit.cyou>2022-12-04 15:06:44 +1000
committerYRabbit <rabbit@yrabbit.cyou>2022-12-04 15:06:44 +1000
commit2e68962a025999ec85276f6362540c13ccfcd752 (patch)
treee1c0d9538a33bce405a5d14ca67baa6ccd1297b9 /gowin
parentf07d9a18356ec8df74d9c42693f7b9307e390a7f (diff)
downloadnextpnr-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>
Diffstat (limited to 'gowin')
-rw-r--r--gowin/arch.cc123
-rw-r--r--gowin/arch.h4
-rw-r--r--gowin/cells.h2
-rw-r--r--gowin/constids.inc3
-rw-r--r--gowin/pack.cc11
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