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 <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,128 @@ 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);
|
||||||
|
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()
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2174,11 +2295,6 @@ void Arch::pre_pack(Context *ctx)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Arch::post_pack(Context *ctx)
|
void Arch::post_pack(Context *ctx) {}
|
||||||
{
|
|
||||||
if (bool_or_default(settings, id("arch.enable-globals"))) {
|
|
||||||
mark_gowin_globals(ctx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
NEXTPNR_NAMESPACE_END
|
NEXTPNR_NAMESPACE_END
|
||||||
|
@ -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);
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user