From 2d45d57b3246814ad20988c6ecf941180faf58a6 Mon Sep 17 00:00:00 2001 From: YRabbit Date: Thu, 26 Jan 2023 20:26:05 +1000 Subject: 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 --- gowin/arch.cc | 98 +++++++++++++++++++++++++++++++++++------------------- gowin/arch.h | 2 +- gowin/cells.cc | 57 +++++++++++++------------------ gowin/cells.h | 5 ++- gowin/constids.inc | 1 - gowin/globals.cc | 42 ++++++++++++++--------- gowin/pack.cc | 24 +++++-------- 7 files changed, 125 insertions(+), 104 deletions(-) diff --git a/gowin/arch.cc b/gowin/arch.cc index f43cc00a..88b9f42f 100644 --- a/gowin/arch.cc +++ b/gowin/arch.cc @@ -1098,16 +1098,33 @@ void Arch::addMuxBels(const DatabasePOD *db, int row, int col) } } -void Arch::add_plla_ports(BelsPOD const *bel, IdString belname, int row, int col) +void Arch::add_pllvr_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_PSDA0, ID_PSDA1, ID_PSDA2, ID_PSDA3, ID_DUTYDA0, - ID_DUTYDA1, ID_DUTYDA2, ID_DUTYDA3, ID_FDLY0, ID_FDLY1, ID_FDLY2, ID_FDLY3}) { + 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_VREN, 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}) { 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))); + 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); @@ -1115,16 +1132,23 @@ void Arch::add_plla_ports(BelsPOD const *bel, IdString belname, int row, int col } } -void Arch::add_pllvr_ports(DatabasePOD const *db, BelsPOD const *bel, IdString belname, int row, int col) +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_VREN, 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}) { - portname = IdString(pairLookup(bel->ports.get(), bel->num_ports, pid)->src_id); + {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; @@ -1137,20 +1161,39 @@ 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); } 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))); + 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; diff --git a/gowin/arch.h b/gowin/arch.h index 0dd5a62b..f060165a 100644 --- a/gowin/arch.h +++ b/gowin/arch.h @@ -478,8 +478,8 @@ struct Arch : BaseArch 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); diff --git a/gowin/cells.cc b/gowin/cells.cc index ae420160..c30a4706 100644 --- a/gowin/cells.cc +++ b/gowin/cells.cc @@ -79,16 +79,12 @@ std::unique_ptr 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,40 +202,33 @@ void gwio_to_iob(Context *ctx, CellInfo *nxio, CellInfo *iob, pool &to } } -void reconnect_rplla(Context *ctx, CellInfo *pll, CellInfo *plla) +void reconnect_pllvr(Context *ctx, CellInfo *pll, CellInfo *new_pll) { - pll->movePortTo(id_CLKIN, plla, id_CLKIN); - pll->movePortTo(id_CLKFB, plla, id_CLKFB); + pll->movePortTo(id_CLKIN, new_pll, id_CLKIN); + pll->movePortTo(id_VREN, new_pll, id_VREN); + 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), 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)); - } + 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), 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(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, 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); + 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 reconnect_pllvr(Context *ctx, CellInfo *pll, CellInfo *new_pll) +void reconnect_rpll(Context *ctx, CellInfo *pll, CellInfo *new_pll) { pll->movePortTo(id_CLKIN, new_pll, id_CLKIN); - pll->movePortTo(id_VREN, new_pll, id_VREN); 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); diff --git a/gowin/cells.h b/gowin/cells.h index 78a746f3..7aba4805 100644 --- a/gowin/cells.h +++ b/gowin/cells.h @@ -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 &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); diff --git a/gowin/constids.inc b/gowin/constids.inc index e3e451a1..dac84a1e 100644 --- a/gowin/constids.inc +++ b/gowin/constids.inc @@ -855,7 +855,6 @@ X(OSCF) // PLLs X(rPLL) X(RPLLA) -X(RPLLB) X(PLLVR) // primitive attributes diff --git a/gowin/globals.cc b/gowin/globals.cc index 6ed8f770..3273191c 100644 --- a/gowin/globals.cc +++ b/gowin/globals.cc @@ -53,7 +53,7 @@ std::pair 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 IdString GowinGlobalRouter::route_to_non_clock_port(Context *ctx, WireId const dstWire, int clock, pool &used_pips, pool &undo_wires) { - static std::vector one_hop = {id_S111, id_S121, id_N111, id_N121, id_W111, id_W121, id_E111, id_E121}; - char buf[40]; + static std::vector one_hop_0 = {id_W111, id_W121, id_E111, id_E121}; + static std::vector 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) { diff --git a/gowin/pack.cc b/gowin/pack.cc index 1ebd5315..cb24ac02 100644 --- a/gowin/pack.cc +++ b/gowin/pack.cc @@ -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 cell = create_generic_cell(ctx, id_RPLLB, ci->name.str(ctx) + "$rpllb"); - reconnect_rpllb(ctx, ci, cell.get()); + // A cell + std::unique_ptr 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: -- cgit v1.2.3