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>
This commit is contained in:
YRabbit 2022-12-04 15:06:44 +10:00
parent f07d9a1835
commit 2e68962a02
5 changed files with 133 additions and 10 deletions

View File

@ -23,6 +23,7 @@
#include <iostream> #include <iostream>
#include <math.h> #include <math.h>
#include <regex> #include <regex>
#include "design_utils.h"
#include "embed.h" #include "embed.h"
#include "gfx.h" #include "gfx.h"
#include "nextpnr.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 // setup pips
for (int i = 0; i < db->rows * db->cols; i++) { for (int i = 0; i < db->rows * db->cols; i++) {
int row = i / db->cols; int row = i / db->cols;
@ -1958,26 +1977,122 @@ bool Arch::place()
return retVal; 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() bool Arch::route()
{ {
std::string router = str_or_default(settings, id_router, defaultRouter); 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"))) { if (bool_or_default(settings, id("arch.enable-globals"))) {
route_gowin_globals(getCtx()); route_gowin_globals(ctx);
} }
bool result; bool result;
if (router == "router1") { if (router == "router1") {
result = router1(getCtx(), Router1Cfg(getCtx())); result = router1(ctx, Router1Cfg(ctx));
} else if (router == "router2") { } else if (router == "router2") {
router2(getCtx(), Router2Cfg(getCtx())); router2(ctx, Router2Cfg(ctx));
result = true; result = true;
} else { } else {
log_error("Gowin architecture does not support router '%s'\n", router.c_str()); log_error("Gowin architecture does not support router '%s'\n", router.c_str());
} }
getCtx()->settings[id_route] = 1; getCtx()->settings[id_route] = 1;
archInfoToAttributes(); archInfoToAttributes();
fix_longwire_bels(); post_route(ctx);
return result; return result;
} }

View File

@ -227,6 +227,7 @@ struct BelInfo
std::map<IdString, std::string> attrs; std::map<IdString, std::string> attrs;
CellInfo *bound_cell; CellInfo *bound_cell;
dict<IdString, PinInfo> pins; dict<IdString, PinInfo> pins;
std::vector<IdString> pin_cfgs;
DecalXY decalxy_active, decalxy_inactive; DecalXY decalxy_active, decalxy_inactive;
int x, y, z; int x, y, z;
bool gb; bool gb;
@ -474,8 +475,11 @@ struct Arch : BaseArch<ArchRanges>
void fix_longwire_bels(); void fix_longwire_bels();
void pre_pack(Context *ctx); void pre_pack(Context *ctx);
void post_pack(Context *ctx); void post_pack(Context *ctx);
void pre_route(Context *ctx);
void post_route(Context *ctx);
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);
GowinGlobalRouter globals_router; GowinGlobalRouter globals_router;
void mark_gowin_globals(Context *ctx); void mark_gowin_globals(Context *ctx);

View File

@ -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_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 // 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 // as needed. Set no_dff if a DFF is not being used, so that the output
// can be reconnected // can be reconnected

View File

@ -938,6 +938,9 @@ X(CLKOUTDIV3)
X(PWDEN) X(PWDEN)
X(RSTEN) X(RSTEN)
X(FLOCK) X(FLOCK)
X(INSEL)
X(FBSEL)
X(CLKFB_SEL)
// timing // timing
X(X0) X(X0)

View File

@ -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 // Pack IO logic
static void pack_iologic(Context *ctx) 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") { if (parm_device == "GW1N-1" || parm_device == "GW1NZ-1") {
// Unused ports will be disabled during image generation. Here we add flags for such ports. // Unused ports will be disabled during image generation. Here we add flags for such ports.
Property pr_enable("ENABLE"), pr_disable("DISABLE"); Property pr_enable("ENABLE"), pr_disable("DISABLE");
IdString ports[][2] = {{id_CLKOUTP, id_CLKOUTPS}, {id_CLKOUTD, id_CLKOUTDIV}, IdString ports[][2] = {{id_CLKOUTP, id_CLKOUTPS},
{id_CLKOUTD3, id_CLKOUTDIV3}, {id_LOCK, id_FLOCK}, {id_CLKOUTD, id_CLKOUTDIV},
{id_RESET_P, id_PWDEN}, {id_RESET, id_RSTEN}}; {id_CLKOUTD3, id_CLKOUTDIV3},
for (int i = 0; i < 6; ++i) { {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); ci->setParam(ports[i][1], port_used(ci, ports[i][0]) ? pr_enable : pr_disable);
} }
// B half // B half