aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--common/kernel/exclusive_state_groups.h5
-rw-r--r--ecp5/arch_place.cc100
-rw-r--r--fpga_interchange/arch.cc6
-rw-r--r--fpga_interchange/luts.cc2
-rw-r--r--fpga_interchange/pseudo_pip_model.cc2
-rw-r--r--gowin/arch.cc98
-rw-r--r--gowin/arch.h2
-rw-r--r--gowin/cells.cc57
-rw-r--r--gowin/cells.h5
-rw-r--r--gowin/constids.inc1
-rw-r--r--gowin/globals.cc42
-rw-r--r--gowin/pack.cc24
12 files changed, 172 insertions, 172 deletions
diff --git a/common/kernel/exclusive_state_groups.h b/common/kernel/exclusive_state_groups.h
index 68ce7c4e..7d447ffe 100644
--- a/common/kernel/exclusive_state_groups.h
+++ b/common/kernel/exclusive_state_groups.h
@@ -125,7 +125,10 @@ template <size_t StateCount, typename StateType = int8_t, typename CountType = u
}
}
- template <typename StateRange> bool requires(const StateRange &state_range) const
+ template <typename StateRange>
+ bool
+ requires(const StateRange &state_range)
+ const
{
if (state < 0) {
return false;
diff --git a/ecp5/arch_place.cc b/ecp5/arch_place.cc
index 2bb601c2..e89e8fb4 100644
--- a/ecp5/arch_place.cc
+++ b/ecp5/arch_place.cc
@@ -200,26 +200,24 @@ bool Arch::isBelLocationValid(BelId bel, bool explain_invalid) const
// Check if this DSP cell placement would result in more than four distinct
// CLK/CE/RST signals per block of two DSP slices.
-bool Arch::is_dsp_location_valid(CellInfo* cell) const
+bool Arch::is_dsp_location_valid(CellInfo *cell) const
{
// Find the location of the DSP0 tile.
int block_x = cell->getLocation().x - cell->getLocation().z;
int block_y = cell->getLocation().y;
- const std::array<std::array<IdString, 4>, 3> block_ports = {{
- {id_CLK0, id_CLK1, id_CLK2, id_CLK3},
- {id_CE0, id_CE1, id_CE2, id_CE3},
- {id_RST0, id_RST1, id_RST2, id_RST3}
- }};
- const std::array<const char*, 3> port_names = {"CLK", "CE", "RST"};
- std::array<std::set<NetInfo*>, 3> block_nets = {};
+ const std::array<std::array<IdString, 4>, 3> block_ports = {{{id_CLK0, id_CLK1, id_CLK2, id_CLK3},
+ {id_CE0, id_CE1, id_CE2, id_CE3},
+ {id_RST0, id_RST1, id_RST2, id_RST3}}};
+ const std::array<const char *, 3> port_names = {"CLK", "CE", "RST"};
+ std::array<std::set<NetInfo *>, 3> block_nets = {};
bool cells_locked = true;
// Count the number of distinct CLK, CE, and RST signals used by
// all the MULT18X18D and ALU54B bels in the DSP block.
for (int dx : {0, 1, 3, 4, 5, 7}) {
BelId dsp_bel = getBelByLocation(Loc(block_x + dx, block_y, dx));
- CellInfo* dsp_cell = getBoundBelCell(dsp_bel);
+ CellInfo *dsp_cell = getBoundBelCell(dsp_bel);
if (dsp_cell == nullptr)
continue;
@@ -240,9 +238,7 @@ bool Arch::is_dsp_location_valid(CellInfo* cell) const
if (cells_locked) {
log_error("DSP block containing %s '%s' has more than "
"four distinct %s signals.\n",
- dsp_cell->type.c_str(getCtx()),
- dsp_cell->name.c_str(getCtx()),
- port_names[i]);
+ dsp_cell->type.c_str(getCtx()), dsp_cell->name.c_str(getCtx()), port_names[i]);
}
return false;
}
@@ -260,12 +256,12 @@ void Arch::remap_dsp_blocks()
std::set<Location> processed_blocks;
const std::array<std::array<IdString, 4>, 3> block_ports = {{
- {id_CLK0, id_CLK1, id_CLK2, id_CLK3},
- {id_CE0, id_CE1, id_CE2, id_CE3},
- {id_RST0, id_RST1, id_RST2, id_RST3},
+ {id_CLK0, id_CLK1, id_CLK2, id_CLK3},
+ {id_CE0, id_CE1, id_CE2, id_CE3},
+ {id_RST0, id_RST1, id_RST2, id_RST3},
}};
- for (auto &cell: cells) {
+ for (auto &cell : cells) {
CellInfo *ci = cell.second.get();
if (!ci->type.in(id_MULT18X18D, id_ALU54B))
continue;
@@ -279,13 +275,13 @@ void Arch::remap_dsp_blocks()
for (auto &ports : block_ports) {
// Store assigned nets for each port.
- std::array<NetInfo*, 4> assigned_nets = {};
+ std::array<NetInfo *, 4> assigned_nets = {};
// Process each possible MULT18X18D or ALU54B in this block.
for (int dx : {0, 1, 3, 4, 5, 7}) {
Loc dsp_loc = Loc(block_loc.x + dx, block_loc.y, dx);
BelId dsp_bel = getBelByLocation(dsp_loc);
- CellInfo* dsp_cell = getBoundBelCell(dsp_bel);
+ CellInfo *dsp_cell = getBoundBelCell(dsp_bel);
if (dsp_cell == nullptr)
continue;
remap_dsp_cell(dsp_cell, ports, assigned_nets);
@@ -314,34 +310,25 @@ void Arch::remap_dsp_blocks()
// ports: array of port names to remap, either CLK0-3 or CE0-3 or RST0-3
// assigned_nets: array of final net assignments to those four ports for
// the block this cell is in.
-void Arch::remap_dsp_cell(
- CellInfo* ci,
- const std::array<IdString, 4> &ports,
- std::array<NetInfo*, 4> &assigned_nets
-) {
+void Arch::remap_dsp_cell(CellInfo *ci, const std::array<IdString, 4> &ports, std::array<NetInfo *, 4> &assigned_nets)
+{
// New names to use in attributes that used to refer to an old port name.
std::array<IdString, 4> remap_ports = {};
// Parameters that might need updating when ports are remapped.
const std::array<IdString, 48> remap_params = {
- id_REG_INPUTA_CLK, id_REG_INPUTA_CE, id_REG_INPUTA_RST,
- id_REG_INPUTB_CLK, id_REG_INPUTB_CE, id_REG_INPUTB_RST,
- id_REG_INPUTC_CLK, id_REG_INPUTC_CE, id_REG_INPUTC_RST,
- id_REG_PIPELINE_CLK, id_REG_PIPELINE_CE, id_REG_PIPELINE_RST,
- id_REG_OUTPUT_CLK, id_REG_OUTPUT_CE, id_REG_OUTPUT_RST,
- id_REG_INPUTC0_CLK, id_REG_INPUTC0_CE, id_REG_INPUTC0_RST,
- id_REG_INPUTC1_CLK, id_REG_INPUTC1_CE, id_REG_INPUTC1_RST,
- id_REG_OPCODEOP0_0_CLK, id_REG_OPCODEOP0_0_CE, id_REG_OPCODEOP0_0_RST,
- id_REG_OPCODEOP1_0_CLK,
- id_REG_OPCODEOP0_1_CLK, id_REG_OPCODEOP0_1_CE, id_REG_OPCODEOP0_1_RST,
- id_REG_OPCODEOP1_1_CLK,
- id_REG_OPCODEIN_0_CLK, id_REG_OPCODEIN_0_CE, id_REG_OPCODEIN_0_RST,
- id_REG_OPCODEIN_1_CLK, id_REG_OPCODEIN_1_CE, id_REG_OPCODEIN_1_RST,
- id_REG_OUTPUT0_CLK, id_REG_OUTPUT0_CE, id_REG_OUTPUT0_RST,
- id_REG_OUTPUT1_CLK, id_REG_OUTPUT1_CE, id_REG_OUTPUT1_RST,
- id_REG_FLAG_CLK, id_REG_FLAG_CE, id_REG_FLAG_RST,
- id_REG_INPUTCFB_CLK, id_REG_INPUTCFB_CE, id_REG_INPUTCFB_RST,
- id_HIGHSPEED_CLK,
+ id_REG_INPUTA_CLK, id_REG_INPUTA_CE, id_REG_INPUTA_RST, id_REG_INPUTB_CLK,
+ id_REG_INPUTB_CE, id_REG_INPUTB_RST, id_REG_INPUTC_CLK, id_REG_INPUTC_CE,
+ id_REG_INPUTC_RST, id_REG_PIPELINE_CLK, id_REG_PIPELINE_CE, id_REG_PIPELINE_RST,
+ id_REG_OUTPUT_CLK, id_REG_OUTPUT_CE, id_REG_OUTPUT_RST, id_REG_INPUTC0_CLK,
+ id_REG_INPUTC0_CE, id_REG_INPUTC0_RST, id_REG_INPUTC1_CLK, id_REG_INPUTC1_CE,
+ id_REG_INPUTC1_RST, id_REG_OPCODEOP0_0_CLK, id_REG_OPCODEOP0_0_CE, id_REG_OPCODEOP0_0_RST,
+ id_REG_OPCODEOP1_0_CLK, id_REG_OPCODEOP0_1_CLK, id_REG_OPCODEOP0_1_CE, id_REG_OPCODEOP0_1_RST,
+ id_REG_OPCODEOP1_1_CLK, id_REG_OPCODEIN_0_CLK, id_REG_OPCODEIN_0_CE, id_REG_OPCODEIN_0_RST,
+ id_REG_OPCODEIN_1_CLK, id_REG_OPCODEIN_1_CE, id_REG_OPCODEIN_1_RST, id_REG_OUTPUT0_CLK,
+ id_REG_OUTPUT0_CE, id_REG_OUTPUT0_RST, id_REG_OUTPUT1_CLK, id_REG_OUTPUT1_CE,
+ id_REG_OUTPUT1_RST, id_REG_FLAG_CLK, id_REG_FLAG_CE, id_REG_FLAG_RST,
+ id_REG_INPUTCFB_CLK, id_REG_INPUTCFB_CE, id_REG_INPUTCFB_RST, id_HIGHSPEED_CLK,
};
// First, go through each port and determine which new port to assign
@@ -363,22 +350,18 @@ void Arch::remap_dsp_cell(
// we need to assign the net to a different port and
// update any attributes that refer to it, while
// ensuring the net at the new port is preserved.
- size_t j = std::distance(
- assigned_nets.cbegin(),
- std::find(assigned_nets.cbegin(), assigned_nets.cend(), nullptr));
+ size_t j = std::distance(assigned_nets.cbegin(),
+ std::find(assigned_nets.cbegin(), assigned_nets.cend(), nullptr));
if (j == assigned_nets.size()) {
log_error("DSP block containing %s '%s': no unused ports "
"to remap %s to; too many distinct signals in "
"block.\n",
- ci->type.c_str(getCtx()),
- ci->name.c_str(getCtx()),
- port.c_str(getCtx()));
+ ci->type.c_str(getCtx()), ci->name.c_str(getCtx()), port.c_str(getCtx()));
}
assigned_nets[j] = net;
remap_ports[i] = ports[j];
- log_info("DSP: %s '%s': Connection to %s remapped to %s\n",
- ci->type.c_str(getCtx()), ci->name.c_str(getCtx()),
- ports[i].c_str(getCtx()), ports[j].c_str(getCtx()));
+ log_info("DSP: %s '%s': Connection to %s remapped to %s\n", ci->type.c_str(getCtx()),
+ ci->name.c_str(getCtx()), ports[i].c_str(getCtx()), ports[j].c_str(getCtx()));
}
} else if (*assigned != assigned_nets[i]) {
// If the net has been assigned already and to a different
@@ -386,9 +369,8 @@ void Arch::remap_dsp_cell(
// to point to the already-assigned port.
size_t j = std::distance(assigned_nets.cbegin(), assigned);
remap_ports[i] = ports[j];
- log_info("DSP: %s '%s': Connection to %s remapped to %s\n",
- ci->type.c_str(getCtx()), ci->name.c_str(getCtx()),
- ports[i].c_str(getCtx()), ports[j].c_str(getCtx()));
+ log_info("DSP: %s '%s': Connection to %s remapped to %s\n", ci->type.c_str(getCtx()),
+ ci->name.c_str(getCtx()), ports[i].c_str(getCtx()), ports[j].c_str(getCtx()));
}
}
@@ -409,10 +391,7 @@ void Arch::remap_dsp_cell(
continue;
for (size_t i = 0; i < remap_ports.size(); i++) {
Property &prop = param->second;
- if (remap_ports[i] != IdString()
- && prop.is_string
- && prop.str == ports[i].str(getCtx())
- ) {
+ if (remap_ports[i] != IdString() && prop.is_string && prop.str == ports[i].str(getCtx())) {
prop = Property(remap_ports[i].str(getCtx()));
break;
}
@@ -421,8 +400,7 @@ void Arch::remap_dsp_cell(
// Finally, only when remapping CLK ports, also move any `CLKn_DIV`
// to the new clock port.
- const std::array<IdString, 4> clk_div_params = {
- id_CLK0_DIV, id_CLK1_DIV, id_CLK2_DIV, id_CLK3_DIV};
+ const std::array<IdString, 4> clk_div_params = {id_CLK0_DIV, id_CLK1_DIV, id_CLK2_DIV, id_CLK3_DIV};
std::array<Property, 4> new_clk_div_props = {};
if (ports[0] == id_CLK0) {
for (size_t i = 0; i < 4; i++) {
@@ -431,9 +409,7 @@ void Arch::remap_dsp_cell(
auto param = ci->params.find(clk_div_params[i]);
if (param == ci->params.end())
continue;
- size_t j = std::distance(
- ports.cbegin(),
- std::find(ports.cbegin(), ports.cend(), remap_ports[i]));
+ size_t j = std::distance(ports.cbegin(), std::find(ports.cbegin(), ports.cend(), remap_ports[i]));
if (j != ports.size()) {
new_clk_div_props[j] = param->second;
}
diff --git a/fpga_interchange/arch.cc b/fpga_interchange/arch.cc
index a1651c81..2682010f 100644
--- a/fpga_interchange/arch.cc
+++ b/fpga_interchange/arch.cc
@@ -46,9 +46,9 @@
// scope of the header.
#include <tcl.h>
-//#define DEBUG_BINDING
-//#define USE_LOOKAHEAD
-//#define DEBUG_CELL_PIN_MAPPING
+// #define DEBUG_BINDING
+// #define USE_LOOKAHEAD
+// #define DEBUG_CELL_PIN_MAPPING
// Define to enable some idempotent sanity checks for some important
// operations prior to placement and routing.
diff --git a/fpga_interchange/luts.cc b/fpga_interchange/luts.cc
index 2a847253..009b601e 100644
--- a/fpga_interchange/luts.cc
+++ b/fpga_interchange/luts.cc
@@ -24,7 +24,7 @@
#include "site_lut_mapping_cache.h"
-//#define DEBUG_LUT_ROTATION
+// #define DEBUG_LUT_ROTATION
NEXTPNR_NAMESPACE_BEGIN
diff --git a/fpga_interchange/pseudo_pip_model.cc b/fpga_interchange/pseudo_pip_model.cc
index 7f2427c4..0b767369 100644
--- a/fpga_interchange/pseudo_pip_model.cc
+++ b/fpga_interchange/pseudo_pip_model.cc
@@ -22,7 +22,7 @@
#include "context.h"
-//#define DEBUG_PSEUDO_PIP
+// #define DEBUG_PSEUDO_PIP
NEXTPNR_NAMESPACE_BEGIN
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<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);
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<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,40 +202,33 @@ void gwio_to_iob(Context *ctx, CellInfo *nxio, CellInfo *iob, pool<IdString> &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<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);
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<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) {
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<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: