gowin: Add PLL support for the GW1NR-9C chip
This chip is used in the Tangnano9k board. * all parameters of the rPLL primitive are supported; * all PLL outputs are treated as clock sources and optimized routing is applied to them; * primitive rPLL on different chips has a completely different structure: for example in GW1N-1 it takes two cells, and in GW1NR-9C as many as four, despite this unification was carried out and different chips are processed by the same functions, but this led to the fact that you can not use the PLL chip GW1N-1 with the old apicula bases - will issue a warning and refuse to encode primitive. In other cases compatibility is supported. * Cosmetic change: the usage report shows the rPLL names without any service bels. * I use ctx->idf() on occasion, it's not a total redesign. Signed-off-by: YRabbit <rabbit@yrabbit.cyou>
This commit is contained in:
parent
9b5e5f124c
commit
2d45d57b32
106
gowin/arch.cc
106
gowin/arch.cc
@ -1098,23 +1098,6 @@ void Arch::addMuxBels(const DatabasePOD *db, int row, int col)
|
||||
}
|
||||
}
|
||||
|
||||
void Arch::add_plla_ports(BelsPOD const *bel, IdString belname, int row, int col)
|
||||
{
|
||||
IdString portname;
|
||||
|
||||
for (int pid : {ID_CLKIN, ID_CLKFB, ID_FBDSEL0, ID_FBDSEL1, ID_FBDSEL2, ID_FBDSEL3, ID_FBDSEL4, ID_FBDSEL5,
|
||||
ID_IDSEL0, ID_IDSEL1, ID_IDSEL2, ID_IDSEL3, ID_IDSEL4, ID_IDSEL5, ID_ODSEL0, ID_ODSEL1,
|
||||
ID_ODSEL2, ID_ODSEL3, ID_ODSEL4, ID_PSDA0, ID_PSDA1, ID_PSDA2, ID_PSDA3, ID_DUTYDA0,
|
||||
ID_DUTYDA1, ID_DUTYDA2, ID_DUTYDA3, ID_FDLY0, ID_FDLY1, ID_FDLY2, ID_FDLY3}) {
|
||||
portname = IdString(pairLookup(bel->ports.get(), bel->num_ports, pid)->src_id);
|
||||
addBelInput(belname, IdString(pid), idf("R%dC%d_%s", row + 1, col + 1, portname.c_str(this)));
|
||||
}
|
||||
for (int pid : {ID_LOCK, ID_CLKOUT, ID_CLKOUTP, ID_CLKOUTD, ID_CLKOUTD3}) {
|
||||
portname = IdString(pairLookup(bel->ports.get(), bel->num_ports, pid)->src_id);
|
||||
addBelOutput(belname, IdString(pid), idf("R%dC%d_%s", row + 1, col + 1, portname.c_str(this)));
|
||||
}
|
||||
}
|
||||
|
||||
void Arch::add_pllvr_ports(DatabasePOD const *db, BelsPOD const *bel, IdString belname, int row, int col)
|
||||
{
|
||||
IdString portname;
|
||||
@ -1137,7 +1120,9 @@ void Arch::add_pllvr_ports(DatabasePOD const *db, BelsPOD const *bel, IdString b
|
||||
int srccol = alias_src->src_col;
|
||||
IdString srcid = IdString(alias_src->src_id);
|
||||
wire = wireToGlobal(srcrow, srccol, db, srcid);
|
||||
// addWire(wire, portname, srccol, srcrow);
|
||||
if (wires.count(wire) == 0) {
|
||||
addWire(wire, srcid, srccol, srcrow);
|
||||
}
|
||||
}
|
||||
addBelInput(belname, IdString(pid), wire);
|
||||
}
|
||||
@ -1146,11 +1131,69 @@ void Arch::add_pllvr_ports(DatabasePOD const *db, BelsPOD const *bel, IdString b
|
||||
addBelOutput(belname, IdString(pid), idf("R%dC%d_%s", row + 1, col + 1, portname.c_str(this)));
|
||||
}
|
||||
}
|
||||
|
||||
void Arch::add_rpll_ports(DatabasePOD const *db, BelsPOD const *bel, IdString belname, int row, int col)
|
||||
{
|
||||
IdString portname;
|
||||
|
||||
for (int pid :
|
||||
{ID_CLKIN, ID_CLKFB, ID_FBDSEL0, ID_FBDSEL1, ID_FBDSEL2, ID_FBDSEL3, ID_FBDSEL4, ID_FBDSEL5, ID_IDSEL0,
|
||||
ID_IDSEL1, ID_IDSEL2, ID_IDSEL3, ID_IDSEL4, ID_IDSEL5, ID_ODSEL0, ID_ODSEL1, ID_ODSEL2, ID_ODSEL3,
|
||||
ID_ODSEL4, ID_ODSEL5, ID_PSDA0, ID_PSDA1, ID_PSDA2, ID_PSDA3, ID_DUTYDA0, ID_DUTYDA1, ID_DUTYDA2,
|
||||
ID_DUTYDA3, ID_FDLY0, ID_FDLY1, ID_FDLY2, ID_FDLY3, ID_RESET, ID_RESET_P}) {
|
||||
const PairPOD *port = pairLookup(bel->ports.get(), bel->num_ports, pid);
|
||||
// old base
|
||||
if (port == nullptr) {
|
||||
log_warning("When building nextpnr, obsolete old apicula bases were used. Probably not working properly "
|
||||
"with PLL.\n");
|
||||
return;
|
||||
}
|
||||
portname = IdString(port->src_id);
|
||||
IdString wire = idf("R%dC%d_%s", row + 1, col + 1, portname.c_str(this));
|
||||
if (wires.count(wire) == 0) {
|
||||
GlobalAliasPOD alias;
|
||||
alias.dest_col = col;
|
||||
alias.dest_row = row;
|
||||
alias.dest_id = portname.hash();
|
||||
auto alias_src = genericLookup(db->aliases.get(), db->num_aliases, alias, aliasCompare);
|
||||
NPNR_ASSERT(alias_src != nullptr);
|
||||
int srcrow = alias_src->src_row;
|
||||
int srccol = alias_src->src_col;
|
||||
IdString srcid = IdString(alias_src->src_id);
|
||||
wire = wireToGlobal(srcrow, srccol, db, srcid);
|
||||
if (wires.count(wire) == 0) {
|
||||
addWire(wire, srcid, srccol, srcrow);
|
||||
}
|
||||
}
|
||||
addBelInput(belname, IdString(pid), wire);
|
||||
}
|
||||
for (int pid : {ID_LOCK, ID_CLKOUT, ID_CLKOUTP, ID_CLKOUTD, ID_CLKOUTD3}) {
|
||||
portname = IdString(pairLookup(bel->ports.get(), bel->num_ports, pid)->src_id);
|
||||
IdString wire = idf("R%dC%d_%s", row + 1, col + 1, portname.c_str(this));
|
||||
if (wires.count(wire) == 0) {
|
||||
GlobalAliasPOD alias;
|
||||
alias.dest_col = col;
|
||||
alias.dest_row = row;
|
||||
alias.dest_id = portname.hash();
|
||||
auto alias_src = genericLookup(db->aliases.get(), db->num_aliases, alias, aliasCompare);
|
||||
NPNR_ASSERT(alias_src != nullptr);
|
||||
int srcrow = alias_src->src_row;
|
||||
int srccol = alias_src->src_col;
|
||||
IdString srcid = IdString(alias_src->src_id);
|
||||
wire = wireToGlobal(srcrow, srccol, db, srcid);
|
||||
if (wires.count(wire) == 0) {
|
||||
addWire(wire, srcid, srccol, srcrow);
|
||||
}
|
||||
}
|
||||
addBelOutput(belname, IdString(pid), wire);
|
||||
}
|
||||
}
|
||||
|
||||
Arch::Arch(ArchArgs args) : args(args)
|
||||
{
|
||||
family = args.family;
|
||||
|
||||
max_clock = 5;
|
||||
max_clock = 6;
|
||||
if (family == "GW1NZ-1") {
|
||||
max_clock = 3;
|
||||
}
|
||||
@ -1312,24 +1355,9 @@ Arch::Arch(ArchArgs args) : args(args)
|
||||
add_pllvr_ports(db, bel, belname, row, col);
|
||||
break;
|
||||
case ID_RPLLA:
|
||||
snprintf(buf, 32, "R%dC%d_RPLLA", row + 1, col + 1);
|
||||
belname = id(buf);
|
||||
addBel(belname, id_RPLLA, Loc(col, row, BelZ::pll_z), false);
|
||||
add_plla_ports(bel, belname, row, col);
|
||||
break;
|
||||
case ID_RPLLB:
|
||||
snprintf(buf, 32, "R%dC%d_RPLLB", row + 1, col + 1);
|
||||
belname = id(buf);
|
||||
addBel(belname, id_RPLLB, Loc(col, row, BelZ::pll_z), false);
|
||||
portname = IdString(pairLookup(bel->ports.get(), bel->num_ports, ID_RESET)->src_id);
|
||||
snprintf(buf, 32, "R%dC%d_%s", row + 1, col + 1, portname.c_str(this));
|
||||
addBelInput(belname, id_RESET, id(buf));
|
||||
portname = IdString(pairLookup(bel->ports.get(), bel->num_ports, ID_RESET_P)->src_id);
|
||||
snprintf(buf, 32, "R%dC%d_%s", row + 1, col + 1, portname.c_str(this));
|
||||
addBelInput(belname, id_RESET_P, id(buf));
|
||||
portname = IdString(pairLookup(bel->ports.get(), bel->num_ports, ID_ODSEL5)->src_id);
|
||||
snprintf(buf, 32, "R%dC%d_%s", row + 1, col + 1, portname.c_str(this));
|
||||
addBelInput(belname, id_ODSEL5, id(buf));
|
||||
belname = idf("R%dC%d_rPLL", row + 1, col + 1);
|
||||
addBel(belname, id_rPLL, Loc(col, row, BelZ::pll_z), false);
|
||||
add_rpll_ports(db, bel, belname, row, col);
|
||||
break;
|
||||
case ID_BUFS7:
|
||||
z++; /* fall-through*/
|
||||
@ -2086,7 +2114,7 @@ void Arch::fix_pll_nets(Context *ctx)
|
||||
{
|
||||
for (auto &cell : ctx->cells) {
|
||||
CellInfo *ci = cell.second.get();
|
||||
if (ci->type != id_RPLLA && ci->type != id_PLLVR) {
|
||||
if (ci->type != id_rPLL && ci->type != id_PLLVR) {
|
||||
continue;
|
||||
}
|
||||
// *** CLKIN
|
||||
@ -2101,7 +2129,7 @@ void Arch::fix_pll_nets(Context *ctx)
|
||||
break;
|
||||
}
|
||||
if (net_driven_by(ctx, net, is_RPLL_T_IN_iob, id_O) != nullptr) {
|
||||
if (ci->type == id_RPLLA) {
|
||||
if (ci->type == id_rPLL) {
|
||||
ci->disconnectPort(id_CLKIN);
|
||||
ci->setParam(id_INSEL, Property("CLKIN0"));
|
||||
break;
|
||||
|
@ -478,8 +478,8 @@ struct Arch : BaseArch<ArchRanges>
|
||||
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 add_pllvr_ports(DatabasePOD const *db, BelsPOD const *bel, IdString belname, int row, int col);
|
||||
void add_rpll_ports(DatabasePOD const *db, BelsPOD const *bel, IdString belname, int row, int col);
|
||||
void fix_pll_nets(Context *ctx);
|
||||
bool is_GCLKT_iob(const CellInfo *cell);
|
||||
|
||||
|
@ -79,16 +79,12 @@ std::unique_ptr<CellInfo> create_generic_cell(Context *ctx, IdString type, std::
|
||||
} else if (type == id_BUFS) {
|
||||
new_cell->addInput(id_I);
|
||||
new_cell->addOutput(id_O);
|
||||
} else if (type == id_RPLLB) {
|
||||
new_cell->addInput(id_RESET);
|
||||
new_cell->addInput(id_RESET_P);
|
||||
new_cell->addInput(id_ODSEL5);
|
||||
} else if (type == id_RPLLA) {
|
||||
} else if (type == id_rPLL) {
|
||||
for (IdString iid :
|
||||
{id_CLKIN, id_CLKFB, id_FBDSEL0, id_FBDSEL1, id_FBDSEL2, id_FBDSEL3, id_FBDSEL4, id_FBDSEL5,
|
||||
id_IDSEL0, id_IDSEL1, id_IDSEL2, id_IDSEL3, id_IDSEL4, id_IDSEL5, id_ODSEL0, id_ODSEL1,
|
||||
id_ODSEL2, id_ODSEL3, id_ODSEL4, id_PSDA0, id_PSDA1, id_PSDA2, id_PSDA3, id_DUTYDA0,
|
||||
id_DUTYDA1, id_DUTYDA2, id_DUTYDA3, id_FDLY0, id_FDLY1, id_FDLY2, id_FDLY3}) {
|
||||
{id_CLKIN, id_CLKFB, id_FBDSEL0, id_FBDSEL1, id_FBDSEL2, id_FBDSEL3, id_FBDSEL4, id_FBDSEL5, id_IDSEL0,
|
||||
id_IDSEL1, id_IDSEL2, id_IDSEL3, id_IDSEL4, id_IDSEL5, id_ODSEL0, id_ODSEL1, id_ODSEL2, id_ODSEL3,
|
||||
id_ODSEL4, id_ODSEL5, id_PSDA0, id_PSDA1, id_PSDA2, id_PSDA3, id_DUTYDA0, id_DUTYDA1, id_DUTYDA2,
|
||||
id_DUTYDA3, id_FDLY0, id_FDLY1, id_FDLY2, id_FDLY3, id_RESET, id_RESET_P}) {
|
||||
new_cell->addInput(iid);
|
||||
}
|
||||
new_cell->addOutput(id_CLKOUT);
|
||||
@ -206,36 +202,6 @@ void gwio_to_iob(Context *ctx, CellInfo *nxio, CellInfo *iob, pool<IdString> &to
|
||||
}
|
||||
}
|
||||
|
||||
void reconnect_rplla(Context *ctx, CellInfo *pll, CellInfo *plla)
|
||||
{
|
||||
pll->movePortTo(id_CLKIN, plla, id_CLKIN);
|
||||
pll->movePortTo(id_CLKFB, plla, id_CLKFB);
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
pll->movePortTo(ctx->idf("FBDSEL[%d]", i), plla, ctx->idf("FBDSEL%d", i));
|
||||
pll->movePortTo(ctx->idf("IDSEL[%d]", i), plla, ctx->idf("IDSEL%d", i));
|
||||
if (i < 5) {
|
||||
pll->movePortTo(ctx->idf("ODSEL[%d]", i), plla, ctx->idf("ODSEL%d", i));
|
||||
}
|
||||
if (i < 4) {
|
||||
pll->movePortTo(ctx->idf("PSDA[%d]", i), plla, ctx->idf("PSDA%d", i));
|
||||
pll->movePortTo(ctx->idf("DUTYDA[%d]", i), plla, ctx->idf("DUTYDA%d", i));
|
||||
pll->movePortTo(ctx->idf("FDLY[%d]", i), plla, ctx->idf("FDLY%d", i));
|
||||
}
|
||||
}
|
||||
pll->movePortTo(id_CLKOUT, plla, id_CLKOUT);
|
||||
pll->movePortTo(id_CLKOUTP, plla, id_CLKOUTP);
|
||||
pll->movePortTo(id_CLKOUTD, plla, id_CLKOUTD);
|
||||
pll->movePortTo(id_CLKOUTD3, plla, id_CLKOUTD3);
|
||||
pll->movePortTo(id_LOCK, plla, id_LOCK);
|
||||
}
|
||||
|
||||
void reconnect_rpllb(Context *ctx, CellInfo *pll, CellInfo *pllb)
|
||||
{
|
||||
pll->movePortTo(id_RESET, pllb, id_RESET);
|
||||
pll->movePortTo(id_RESET_P, pllb, id_RESET_P);
|
||||
pll->movePortTo(ctx->id("ODSEL[5]"), pllb, id_ODSEL5);
|
||||
}
|
||||
|
||||
void reconnect_pllvr(Context *ctx, CellInfo *pll, CellInfo *new_pll)
|
||||
{
|
||||
pll->movePortTo(id_CLKIN, new_pll, id_CLKIN);
|
||||
@ -260,6 +226,29 @@ void reconnect_pllvr(Context *ctx, CellInfo *pll, CellInfo *new_pll)
|
||||
pll->movePortTo(id_LOCK, new_pll, id_LOCK);
|
||||
}
|
||||
|
||||
void reconnect_rpll(Context *ctx, CellInfo *pll, CellInfo *new_pll)
|
||||
{
|
||||
pll->movePortTo(id_CLKIN, new_pll, id_CLKIN);
|
||||
pll->movePortTo(id_CLKFB, new_pll, id_CLKFB);
|
||||
pll->movePortTo(id_RESET, new_pll, id_RESET);
|
||||
pll->movePortTo(id_RESET_P, new_pll, id_RESET_P);
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
pll->movePortTo(ctx->idf("FBDSEL[%d]", i), new_pll, ctx->idf("FBDSEL%d", i));
|
||||
pll->movePortTo(ctx->idf("IDSEL[%d]", i), new_pll, ctx->idf("IDSEL%d", i));
|
||||
pll->movePortTo(ctx->idf("ODSEL[%d]", i), new_pll, ctx->idf("ODSEL%d", i));
|
||||
if (i < 4) {
|
||||
pll->movePortTo(ctx->idf("PSDA[%d]", i), new_pll, ctx->idf("PSDA%d", i));
|
||||
pll->movePortTo(ctx->idf("DUTYDA[%d]", i), new_pll, ctx->idf("DUTYDA%d", i));
|
||||
pll->movePortTo(ctx->idf("FDLY[%d]", i), new_pll, ctx->idf("FDLY%d", i));
|
||||
}
|
||||
}
|
||||
pll->movePortTo(id_CLKOUT, new_pll, id_CLKOUT);
|
||||
pll->movePortTo(id_CLKOUTP, new_pll, id_CLKOUTP);
|
||||
pll->movePortTo(id_CLKOUTD, new_pll, id_CLKOUTD);
|
||||
pll->movePortTo(id_CLKOUTD3, new_pll, id_CLKOUTD3);
|
||||
pll->movePortTo(id_LOCK, new_pll, id_LOCK);
|
||||
}
|
||||
|
||||
void sram_to_ramw_split(Context *ctx, CellInfo *ram, CellInfo *ramw)
|
||||
{
|
||||
if (ramw->hierpath == IdString())
|
||||
|
@ -122,9 +122,8 @@ void dff_to_lc(const Context *ctx, CellInfo *dff, CellInfo *lc, bool pass_thru_l
|
||||
void gwio_to_iob(Context *ctx, CellInfo *nxio, CellInfo *sbio, pool<IdString> &todelete_cells);
|
||||
|
||||
// Reconnect PLL signals (B)
|
||||
void reconnect_pllvr(Context *ctx, CellInfo *pll, CellInfo *pllb);
|
||||
void reconnect_rplla(Context *ctx, CellInfo *pll, CellInfo *pllb);
|
||||
void reconnect_rpllb(Context *ctx, CellInfo *pll, CellInfo *pllb);
|
||||
void reconnect_pllvr(Context *ctx, CellInfo *pll, CellInfo *new_pll);
|
||||
void reconnect_rpll(Context *ctx, CellInfo *pll, CellInfo *new_pll);
|
||||
|
||||
// Convert RAM16 to write port
|
||||
void sram_to_ramw_split(Context *ctx, CellInfo *ram, CellInfo *ramw);
|
||||
|
@ -855,7 +855,6 @@ X(OSCF)
|
||||
// PLLs
|
||||
X(rPLL)
|
||||
X(RPLLA)
|
||||
X(RPLLB)
|
||||
X(PLLVR)
|
||||
|
||||
// primitive attributes
|
||||
|
@ -53,7 +53,7 @@ std::pair<WireId, BelId> GowinGlobalRouter::clock_src(Context *ctx, PortRef cons
|
||||
}
|
||||
return std::make_pair(WireId(), BelId());
|
||||
}
|
||||
if (driver.cell->type == id_RPLLA || driver.cell->type == id_PLLVR) {
|
||||
if (driver.cell->type == id_rPLL || driver.cell->type == id_PLLVR) {
|
||||
if (driver.port == id_CLKOUT || driver.port == id_CLKOUTP || driver.port == id_CLKOUTD ||
|
||||
driver.port == id_CLKOUTD3) {
|
||||
wire = bel.pins[driver.port].wire;
|
||||
@ -103,12 +103,20 @@ void GowinGlobalRouter::gather_clock_nets(Context *ctx, std::vector<globalnet_t>
|
||||
IdString GowinGlobalRouter::route_to_non_clock_port(Context *ctx, WireId const dstWire, int clock,
|
||||
pool<IdString> &used_pips, pool<IdString> &undo_wires)
|
||||
{
|
||||
static std::vector<IdString> one_hop = {id_S111, id_S121, id_N111, id_N121, id_W111, id_W121, id_E111, id_E121};
|
||||
char buf[40];
|
||||
static std::vector<IdString> one_hop_0 = {id_W111, id_W121, id_E111, id_E121};
|
||||
static std::vector<IdString> one_hop_4 = {id_S111, id_S121, id_N111, id_N121};
|
||||
// uphill pips
|
||||
for (auto const uphill : ctx->getPipsUphill(dstWire)) {
|
||||
WireId srcWire = ctx->getPipSrcWire(uphill);
|
||||
if (find(one_hop.begin(), one_hop.end(), ctx->wire_info(ctx->getPipSrcWire(uphill)).type) != one_hop.end()) {
|
||||
bool found;
|
||||
if (clock < 4) {
|
||||
found = find(one_hop_0.begin(), one_hop_0.end(), ctx->wire_info(ctx->getPipSrcWire(uphill)).type) !=
|
||||
one_hop_0.end();
|
||||
} else {
|
||||
found = find(one_hop_4.begin(), one_hop_4.end(), ctx->wire_info(ctx->getPipSrcWire(uphill)).type) !=
|
||||
one_hop_4.end();
|
||||
}
|
||||
if (found) {
|
||||
// found one hop pip
|
||||
if (used_wires.count(srcWire)) {
|
||||
if (used_wires[srcWire] != clock) {
|
||||
@ -117,8 +125,13 @@ IdString GowinGlobalRouter::route_to_non_clock_port(Context *ctx, WireId const d
|
||||
}
|
||||
WireInfo wi = ctx->wire_info(srcWire);
|
||||
std::string wire_alias = srcWire.str(ctx).substr(srcWire.str(ctx).rfind("_") + 1);
|
||||
snprintf(buf, sizeof(buf), "R%dC%d_GB%d0_%s", wi.y + 1, wi.x + 1, clock, wire_alias.c_str());
|
||||
IdString gb = ctx->id(buf);
|
||||
IdString gb = ctx->idf("R%dC%d_GB%d0_%s", wi.y + 1, wi.x + 1, clock, wire_alias.c_str());
|
||||
if (ctx->verbose) {
|
||||
log_info(" 1-hop gb:%s\n", gb.c_str(ctx));
|
||||
}
|
||||
// sanity
|
||||
NPNR_ASSERT(find(ctx->getPipsUphill(srcWire).begin(), ctx->getPipsUphill(srcWire).end(), gb) !=
|
||||
ctx->getPipsUphill(srcWire).end());
|
||||
auto up_pips = ctx->getPipsUphill(srcWire);
|
||||
if (find(up_pips.begin(), up_pips.end(), gb) != up_pips.end()) {
|
||||
if (!used_wires.count(srcWire)) {
|
||||
@ -154,11 +167,10 @@ void GowinGlobalRouter::route_net(Context *ctx, globalnet_t const &net)
|
||||
|
||||
char buf[30];
|
||||
PipId gb_pip_id;
|
||||
if (user.port == id_CLK) {
|
||||
if (user.port == id_CLK || user.port == id_CLKIN) {
|
||||
WireInfo const wi = ctx->wire_info(dstWire);
|
||||
snprintf(buf, sizeof(buf), "R%dC%d_GB%d0_%s", wi.y + 1, wi.x + 1, net.clock,
|
||||
ctx->wire_info(dstWire).type.c_str(ctx));
|
||||
gb_pip_id = ctx->id(buf);
|
||||
gb_pip_id =
|
||||
ctx->idf("R%dC%d_GB%d0_%s", wi.y + 1, wi.x + 1, net.clock, ctx->wire_info(dstWire).type.c_str(ctx));
|
||||
// sanity
|
||||
NPNR_ASSERT(find(ctx->getPipsUphill(dstWire).begin(), ctx->getPipsUphill(dstWire).end(), gb_pip_id) !=
|
||||
ctx->getPipsUphill(dstWire).end());
|
||||
@ -192,11 +204,10 @@ void GowinGlobalRouter::route_net(Context *ctx, globalnet_t const &net)
|
||||
dstWire = ctx->getPipSrcWire(gb_pip_id);
|
||||
WireInfo dstWireInfo = ctx->wire_info(dstWire);
|
||||
int branch_tap_idx = net.clock > 3 ? 1 : 0;
|
||||
snprintf(buf, sizeof(buf), "R%dC%d_GT%d0_GBO%d", dstWireInfo.y + 1, dstWireInfo.x + 1, branch_tap_idx,
|
||||
branch_tap_idx);
|
||||
PipId gt_pip_id = ctx->id(buf);
|
||||
PipId gt_pip_id =
|
||||
ctx->idf("R%dC%d_GT%d0_GBO%d", dstWireInfo.y + 1, dstWireInfo.x + 1, branch_tap_idx, branch_tap_idx);
|
||||
if (ctx->verbose) {
|
||||
log_info(" GT Pip:%s\n", buf);
|
||||
log_info(" GT Pip:%s\n", gt_pip_id.c_str(ctx));
|
||||
}
|
||||
// sanity
|
||||
NPNR_ASSERT(find(ctx->getPipsUphill(dstWire).begin(), ctx->getPipsUphill(dstWire).end(), gt_pip_id) !=
|
||||
@ -251,12 +262,13 @@ void GowinGlobalRouter::route_net(Context *ctx, globalnet_t const &net)
|
||||
for (auto const uphill_pip : ctx->getPipsUphill(dstWire)) {
|
||||
if (ctx->getPipSrcWire(uphill_pip) == net.clock_wire) {
|
||||
src_pip_id = uphill_pip;
|
||||
break;
|
||||
}
|
||||
}
|
||||
NPNR_ASSERT(src_pip_id != PipId());
|
||||
if (ctx->verbose) {
|
||||
log_info(" Src Pip:%s\n", src_pip_id.c_str(ctx));
|
||||
}
|
||||
NPNR_ASSERT(src_pip_id != PipId());
|
||||
// if already routed
|
||||
if (used_pips.count(src_pip_id)) {
|
||||
if (ctx->verbose) {
|
||||
|
@ -1034,7 +1034,7 @@ static void pack_plls(Context *ctx)
|
||||
if (ctx->verbose)
|
||||
log_info("cell '%s' is of type '%s'\n", ctx->nameOf(ci), ci->type.c_str(ctx));
|
||||
if (is_pll(ctx, ci)) {
|
||||
std::string parm_device = str_or_default(ci->params, id_DEVICE, "GW1N-1");
|
||||
std::string parm_device = str_or_default(ci->params, id_DEVICE, ctx->device.c_str());
|
||||
if (parm_device != ctx->device) {
|
||||
log_error("Cell '%s': wrong PLL device:%s instead of %s\n", ctx->nameOf(ci), parm_device.c_str(),
|
||||
ctx->device.c_str());
|
||||
@ -1043,27 +1043,21 @@ static void pack_plls(Context *ctx)
|
||||
|
||||
switch (ci->type.hash()) {
|
||||
case ID_rPLL: {
|
||||
if (parm_device == "GW1N-1" || parm_device == "GW1NZ-1") {
|
||||
if (parm_device == "GW1N-1" || parm_device == "GW1NZ-1" || parm_device == "GW1NR-9C") {
|
||||
pll_disable_unused_ports(ctx, ci);
|
||||
// B half
|
||||
std::unique_ptr<CellInfo> cell = create_generic_cell(ctx, id_RPLLB, ci->name.str(ctx) + "$rpllb");
|
||||
reconnect_rpllb(ctx, ci, cell.get());
|
||||
// A cell
|
||||
std::unique_ptr<CellInfo> cell = create_generic_cell(ctx, id_rPLL, ci->name.str(ctx) + "$rpll");
|
||||
reconnect_rpll(ctx, ci, cell.get());
|
||||
new_cells.push_back(std::move(cell));
|
||||
auto pllb_cell = new_cells.back().get();
|
||||
// A half
|
||||
cell = create_generic_cell(ctx, id_RPLLA, ci->name.str(ctx) + "$rplla");
|
||||
reconnect_rplla(ctx, ci, cell.get());
|
||||
new_cells.push_back(std::move(cell));
|
||||
auto plla_cell = new_cells.back().get();
|
||||
auto pll_cell = new_cells.back().get();
|
||||
|
||||
// need params for gowin_pack
|
||||
for (auto &parm : ci->params) {
|
||||
plla_cell->setParam(parm.first, parm.second);
|
||||
pllb_cell->setParam(parm.first, parm.second);
|
||||
pll_cell->setParam(parm.first, parm.second);
|
||||
}
|
||||
packed_cells.insert(ci->name);
|
||||
} else {
|
||||
log_error("PLL isn't supported for %s\n", ctx->device.c_str());
|
||||
log_error("rPLL isn't supported for %s\n", ctx->device.c_str());
|
||||
}
|
||||
} break;
|
||||
case ID_PLLVR: {
|
||||
@ -1080,7 +1074,7 @@ static void pack_plls(Context *ctx)
|
||||
}
|
||||
packed_cells.insert(ci->name);
|
||||
} else {
|
||||
log_error("PLL isn't supported for %s\n", ctx->device.c_str());
|
||||
log_error("PLLVR isn't supported for %s\n", ctx->device.c_str());
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
|
Loading…
Reference in New Issue
Block a user