Merge pull request #1055 from yrabbit/pll-pins
gowin: add PLL pins processing
This commit is contained in:
commit
a342b96bb0
136
gowin/arch.cc
136
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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -938,6 +938,9 @@ X(CLKOUTDIV3)
|
||||
X(PWDEN)
|
||||
X(RSTEN)
|
||||
X(FLOCK)
|
||||
X(INSEL)
|
||||
X(FBSEL)
|
||||
X(CLKFB_SEL)
|
||||
|
||||
// timing
|
||||
X(X0)
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user