From db696af2fe53ab4dc341a09303bb6cd371d76519 Mon Sep 17 00:00:00 2001 From: YRabbit Date: Fri, 27 May 2022 22:44:21 +1000 Subject: [PATCH 1/7] gowin: Add support for long wires Gowin chips have a highly sophisticated system of long wires that are wired to each cell and allow the clock or logic to spread quickly. This commit implements some of the capabilities of the long wire system for quadrants, leaving out the fine-tuning of them for each column. To make use of the long wire system, the specified wire is cut at the driver and a special cell is placed between the driver and the rest of the wire. * VCC and GND can not use long wires because they are in every cell and there is no point in using a net * Long wire numbers can be specified manually or assigned automatically. * The route from the driver to the port of the new cell can be quite long, this will have to be solved somehow. * It might make sense to add a mechanism for automatically finding candidates for long wires. Signed-off-by: YRabbit --- gowin/arch.cc | 206 ++++++++++++++++++++++++++++++++++++++++++++- gowin/arch.h | 10 ++- gowin/cells.cc | 3 + gowin/constids.inc | 80 ++++++++++++++++++ gowin/pack.cc | 8 +- 5 files changed, 299 insertions(+), 8 deletions(-) diff --git a/gowin/arch.cc b/gowin/arch.cc index 4fc2cd43..a991879e 100644 --- a/gowin/arch.cc +++ b/gowin/arch.cc @@ -19,6 +19,7 @@ */ #include +#include #include #include #include @@ -175,6 +176,145 @@ DecalXY Arch::getWireDecal(WireId wire) const return wires.at(wire).decalxy_active; } +bool Arch::allocate_longwire(NetInfo *ni, int lw_idx) +{ + NPNR_ASSERT(ni != nullptr); + if (ni->driver.cell == nullptr) { + return false; + } + if (ni->name == id("$PACKER_VCC_NET") || ni->name == id("$PACKER_GND_NET")) { + return false; + } + // So far only for OBUF + switch (ni->driver.cell->type.index) { + case ID_ODDR: /* fall-through*/ + case ID_ODDRC: /* fall-through*/ + case ID_IOBUF: /* fall-through*/ + case ID_TBUF: + return false; + case ID_OBUF: + if (getCtx()->debug) { + log_info("Long wire for IO %s\n", nameOf(ni)); + } + ni = ni->driver.cell->ports.at(id_I).net; + return allocate_longwire(ni, lw_idx); + break; + default: + break; + } + + if (getCtx()->debug) { + log_info("Requested index:%d\n", lw_idx); + } + if (avail_longwires == 0 || (lw_idx != -1 && (avail_longwires & (1 << lw_idx)) == 0)) { + return false; + } + int longwire = lw_idx; + if (lw_idx == -1) { + for (longwire = 7; longwire >= 0; --longwire) { + if (avail_longwires & (1 << longwire)) { + break; + } + } + } + avail_longwires &= ~(1 << longwire); + + // BUFS cell + CellInfo *bufs; + char buf[40]; + snprintf(buf, sizeof(buf), "$PACKER_BUFS%d", longwire); + std::unique_ptr new_cell = create_generic_cell(getCtx(), id_BUFS, buf); + bufs = new_cell.get(); + cells[bufs->name] = std::move(new_cell); + if (lw_idx != -1) { + bufs->cluster = bufs->name; + bufs->constr_z = lw_idx + BelZ::bufs_0_z; + bufs->constr_abs_z = true; + bufs->constr_children.clear(); + } + + // old driver -> bufs LW input net + snprintf(buf, sizeof(buf), "$PACKER_BUFS_%c", longwire + 'A'); + auto net = std::make_unique(id(buf)); + NetInfo *bufs_net = net.get(); + nets[net->name] = std::move(net); + + // split the net + CellInfo *driver_cell = ni->driver.cell; + IdString driver_port = ni->driver.port; + driver_cell->disconnectPort(driver_port); + + bufs->connectPort(id_O, ni); + bufs->connectPort(id_I, bufs_net); + driver_cell->connectPort(driver_port, bufs_net); + + if (getCtx()->debug) { + log_info("Long wire %d was allocated\n", longwire); + } + return true; +} + +void Arch::fix_longwire_bels() +{ + // After routing, it is clear which wires and in which bus SS00 and SS40 are used and + // in which quadrant they are routed. Here we write it in the attributes. + for (auto &cell : cells) { + CellInfo *ci = cell.second.get(); + if (ci->type != id_BUFS) { + continue; + } + const NetInfo *ni = ci->getPort(id_O); + if (ni == nullptr) { + continue; + } + // bus wire is one of the wires + // value does not matter, but the L/R parameter itself + for (auto &wire : ni->wires) { + WireId w = wires[wire.first].type; + switch (w.hash()) { + case ID_LWSPINETL0: + case ID_LWSPINETL1: + case ID_LWSPINETL2: + case ID_LWSPINETL3: + case ID_LWSPINETL4: + case ID_LWSPINETL5: + case ID_LWSPINETL6: + case ID_LWSPINETL7: + case ID_LWSPINEBL0: + case ID_LWSPINEBL1: + case ID_LWSPINEBL2: + case ID_LWSPINEBL3: + case ID_LWSPINEBL4: + case ID_LWSPINEBL5: + case ID_LWSPINEBL6: + case ID_LWSPINEBL7: + ci->setParam(id("L"), Property(w.str(this))); + break; + case ID_LWSPINETR0: + case ID_LWSPINETR1: + case ID_LWSPINETR2: + case ID_LWSPINETR3: + case ID_LWSPINETR4: + case ID_LWSPINETR5: + case ID_LWSPINETR6: + case ID_LWSPINETR7: + case ID_LWSPINEBR0: + case ID_LWSPINEBR1: + case ID_LWSPINEBR2: + case ID_LWSPINEBR3: + case ID_LWSPINEBR4: + case ID_LWSPINEBR5: + case ID_LWSPINEBR6: + case ID_LWSPINEBR7: + ci->setParam(id("R"), Property(w.str(this))); + break; + default: + break; + } + } + } +} + WireInfo &Arch::wire_info(IdString wire) { auto w = wires.find(wire); @@ -628,6 +768,28 @@ DelayQuad Arch::getWireTypeDelay(IdString wire) case ID_W830: len = id_X8; break; + case ID_LT02: + case ID_LT13: + glbsrc = id_SPINE_TAP_SCLK_0; + break; + case ID_LT01: + case ID_LT04: + glbsrc = id_SPINE_TAP_SCLK_1; + break; + case ID_LBO0: + case ID_LBO1: + glbsrc = id_TAP_BRANCH_SCLK; + break; + case ID_LB01: + case ID_LB11: + case ID_LB21: + case ID_LB31: + case ID_LB41: + case ID_LB51: + case ID_LB61: + case ID_LB71: + glbsrc = id_BRANCH_SCLK; + break; case ID_GT00: case ID_GT10: glbsrc = id_SPINE_TAP_PCLK; @@ -647,7 +809,9 @@ DelayQuad Arch::getWireTypeDelay(IdString wire) glbsrc = id_BRANCH_PCLK; break; default: - if (wire.str(this).rfind("SPINE", 0) == 0) { + if (wire.str(this).rfind("LWSPINE", 0) == 0) { + glbsrc = IdString(ID_CENT_SPINE_SCLK); + } else if (wire.str(this).rfind("SPINE", 0) == 0) { glbsrc = IdString(ID_CENT_SPINE_PCLK); } else if (wire.str(this).rfind("UNK", 0) == 0) { glbsrc = IdString(ID_PIO_CENT_PCLK); @@ -691,7 +855,7 @@ void Arch::read_cst(std::istream &in) std::regex port_attrre = std::regex("([^ =;]+=[^ =;]+) *([^;]*;)"); std::regex iobelre = std::regex("IO([TRBL])([0-9]+)\\[?([A-Z])\\]?"); std::regex inslocre = std::regex("INS_LOC +\"([^\"]+)\" +R([0-9]+)C([0-9]+)\\[([0-9])\\]\\[([AB])\\] *;.*"); - std::regex clockre = std::regex("CLOCK_LOC +\"([^\"]+)\" +BUF([GS])[^;]*;"); + std::regex clockre = std::regex("CLOCK_LOC +\"([^\"]+)\" +BUF([GS])(\\[([0-7])\\])?[^;]*;.*"); std::smatch match, match_attr, match_pinloc; std::string line, pinline; enum @@ -732,15 +896,23 @@ void Arch::read_cst(std::istream &in) continue; } switch (cst_type) { - case clock: { // CLOCK name BUFG|S + case clock: { // CLOCK name BUFG|S=# std::string which_clock = match[2]; + std::string lw = match[4]; + int lw_idx = -1; + if (lw.length() > 0) { + lw_idx = atoi(lw.c_str()); + log_info("lw_idx:%d\n", lw_idx); + } if (which_clock.at(0) == 'S') { auto ni = nets.find(net); if (ni == nets.end()) { log_info("Net %s not found\n", net.c_str(this)); continue; } - log_info("Long wires are not implemented. The %s network will use normal routing.\n", net.c_str(this)); + if (!allocate_longwire(ni->second.get(), lw_idx)) { + log_info("Can't use the long wires. The %s network will use normal routing.\n", net.c_str(this)); + } } else { log_info("BUFG isn't supported\n"); continue; @@ -1021,6 +1193,31 @@ Arch::Arch(ArchArgs args) : args(args) bool dff = true; bool oddrc = false; switch (static_cast(bel->type_id)) { + case ID_BUFS7: + z++; /* fall-through*/ + case ID_BUFS6: + z++; /* fall-through*/ + case ID_BUFS5: + z++; /* fall-through*/ + case ID_BUFS4: + z++; /* fall-through*/ + case ID_BUFS3: + z++; /* fall-through*/ + case ID_BUFS2: + z++; /* fall-through*/ + case ID_BUFS1: + z++; /* fall-through*/ + case ID_BUFS0: + snprintf(buf, 32, "R%dC%d_BUFS%d", row + 1, col + 1, z); + belname = id(buf); + addBel(belname, id_BUFS, Loc(col, row, BelZ::bufs_0_z + z), false); + portname = IdString(pairLookup(bel->ports.get(), bel->num_ports, ID_I)->src_id); + snprintf(buf, 32, "R%dC%d_%s", row + 1, col + 1, portname.c_str(this)); + addBelInput(belname, id_I, id(buf)); + portname = IdString(pairLookup(bel->ports.get(), bel->num_ports, ID_O)->src_id); + snprintf(buf, 32, "R%dC%d_%s", row + 1, col + 1, portname.c_str(this)); + addBelOutput(belname, id_O, id(buf)); + break; case ID_GSR0: snprintf(buf, 32, "R%dC%d_GSR0", row + 1, col + 1); belname = id(buf); @@ -1675,6 +1872,7 @@ bool Arch::route() } getCtx()->settings[id_route] = 1; archInfoToAttributes(); + fix_longwire_bels(); return result; } diff --git a/gowin/arch.h b/gowin/arch.h index 14181d79..8bbbd514 100644 --- a/gowin/arch.h +++ b/gowin/arch.h @@ -459,6 +459,9 @@ struct Arch : BaseArch void assignArchInfo() override; bool cellsCompatible(const CellInfo **cells, int count) const; bool haveBelType(int x, int y, IdString bel_type); + bool allocate_longwire(NetInfo *ni, int lw_idx = -1); + void fix_longwire_bels(); + // chip db version unsigned int const chipdb_version = 1; @@ -475,6 +478,9 @@ struct Arch : BaseArch // XXX GW1NR-9 iobuf quirk bool gw1n9_quirk = false; + // 8 Long wires + uint8_t avail_longwires = 0xff; + // Permissible combinations of modes in a single slice std::map dff_comp_mode; }; @@ -487,7 +493,9 @@ enum iologic_0_z = 20, // start Z for the IOLOGIC bels vcc_0_z = 277, // virtual VCC bel Z gnd_0_z = 278, // virtual VSS bel Z - osc_z = 280 // Z for the oscillator bels + osc_z = 280, // Z for the oscillator bels + bufs_0_z = 281, // Z for long wire buffer bel + free_z = 289 // Must be the last, one can use z starting from this value, adjust accordingly. }; } diff --git a/gowin/cells.cc b/gowin/cells.cc index c3b21782..6010164a 100644 --- a/gowin/cells.cc +++ b/gowin/cells.cc @@ -69,6 +69,9 @@ std::unique_ptr create_generic_cell(Context *ctx, IdString type, std:: new_cell->addOutput(id_G); } else if (type == id_VCC) { new_cell->addOutput(id_V); + } else if (type == id_BUFS) { + new_cell->addInput(id_I); + new_cell->addOutput(id_O); } else { log_error("unable to create generic cell of type %s\n", type.c_str(ctx)); } diff --git a/gowin/constids.inc b/gowin/constids.inc index 3691c506..99c791f8 100644 --- a/gowin/constids.inc +++ b/gowin/constids.inc @@ -679,6 +679,81 @@ X(IOBHS) X(IOBIS) X(IOBJS) +// long wires +X(BUFS) +X(BUFS0) +X(BUFS1) +X(BUFS2) +X(BUFS3) +X(BUFS4) +X(BUFS5) +X(BUFS6) +X(BUFS7) +X(LWT0) +X(LWB0) +X(LWT1) +X(LWB1) +X(LWT2) +X(LWB2) +X(LWT3) +X(LWB3) +X(LWT4) +X(LWB4) +X(LWT5) +X(LWB5) +X(LWT6) +X(LWB6) +X(LWT7) +X(LWB7) +X(LWSPINETL0) +X(LWSPINETL1) +X(LWSPINETL2) +X(LWSPINETL3) +X(LWSPINETL4) +X(LWSPINETL5) +X(LWSPINETL6) +X(LWSPINETL7) +X(LWSPINETR0) +X(LWSPINETR1) +X(LWSPINETR2) +X(LWSPINETR3) +X(LWSPINETR4) +X(LWSPINETR5) +X(LWSPINETR6) +X(LWSPINETR7) +X(LWSPINEBL0) +X(LWSPINEBL1) +X(LWSPINEBL2) +X(LWSPINEBL3) +X(LWSPINEBL4) +X(LWSPINEBL5) +X(LWSPINEBL6) +X(LWSPINEBL7) +X(LWSPINEBR0) +X(LWSPINEBR1) +X(LWSPINEBR2) +X(LWSPINEBR3) +X(LWSPINEBR4) +X(LWSPINEBR5) +X(LWSPINEBR6) +X(LWSPINEBR7) +X(LWI0) +X(LWI1) +X(LWI2) +X(LWI3) +X(LWI4) +X(LWI5) +X(LWI6) +X(LWI7) +X(LWO0) +X(LWO1) +X(LWO2) +X(LWO3) +X(LWO4) +X(LWO5) +X(LWO6) +X(LWO7) + // IOLOGIC X(TX) X(XXX_VSS) @@ -812,6 +887,11 @@ X(CENT_SPINE_PCLK) X(SPINE_TAP_PCLK) X(TAP_BRANCH_PCLK) X(BRANCH_PCLK) +X(CENT_SPINE_SCLK) +X(SPINE_TAP_SCLK_0) +X(SPINE_TAP_SCLK_1) +X(TAP_BRANCH_SCLK) +X(BRANCH_SCLK) X(clksetpos) X(clkholdpos) X(clk_qpos) diff --git a/gowin/pack.cc b/gowin/pack.cc index 4adfec1a..83820142 100644 --- a/gowin/pack.cc +++ b/gowin/pack.cc @@ -947,9 +947,11 @@ static void pack_io(Context *ctx) if (constr_bel != ci->attrs.end()) { constr_bel_name = constr_bel->second.as_string(); } - constr_bel = iob->attrs.find(id_BEL); - if (constr_bel != iob->attrs.end()) { - constr_bel_name = constr_bel->second.as_string(); + if (iob != nullptr) { + constr_bel = iob->attrs.find(id_BEL); + if (constr_bel != iob->attrs.end()) { + constr_bel_name = constr_bel->second.as_string(); + } } if (!constr_bel_name.empty()) { BelId constr_bel = ctx->getBelByNameStr(constr_bel_name); From bd0af4052c434b1cf3ed8522360b5acc78bd17a2 Mon Sep 17 00:00:00 2001 From: YRabbit Date: Thu, 9 Jun 2022 08:20:29 +1000 Subject: [PATCH 2/7] gowin: Use local aliases In the Gowin chips, the tiles are connected to each other by a one-hop wire, among others. There are 4 one-hop wires, of which 2 are shared between north/south and east/west, have three names: e.g. SN10 and N110 and S110. But only one of them, the first, occurs as a sink for PIP, that is, you can not get a route that would pass through the S110 for example. This commit corrects the names to SN?0 and EW?0 at the wire creation stage to avoid dead wires. In addition, the SN?0 and EW?0 are among the few sinks for global clock wires and now there is the possibility of a more optimal clock routing. Signed-off-by: YRabbit --- gowin/arch.cc | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/gowin/arch.cc b/gowin/arch.cc index a991879e..82f5018b 100644 --- a/gowin/arch.cc +++ b/gowin/arch.cc @@ -34,6 +34,8 @@ NEXTPNR_NAMESPACE_BEGIN +const PairPOD *pairLookup(const PairPOD *list, const size_t len, const int dest); + // GUI void Arch::fixClockSpineDecals(void) { @@ -627,7 +629,15 @@ IdString Arch::wireToGlobal(int &row, int &col, const DatabasePOD *db, IdString } snprintf(buf, 32, "%c%d0", direction, num); wire = id(buf); - snprintf(buf, 32, "R%dC%d_%c%d", row + 1, col + 1, direction, num); + // local aliases + const TilePOD *tile = db->grid[row * db->cols + col].get(); + auto local_alias = pairLookup(tile->aliases.get(), tile->num_aliases, wire.index); + if (local_alias != nullptr) { + wire = IdString(local_alias->src_id); + snprintf(buf, 32, "R%dC%d_%s", row + 1, col + 1, wire.c_str(this)); + } else { + snprintf(buf, 32, "R%dC%d_%c%d", row + 1, col + 1, direction, num); + } return id(buf); } @@ -1491,12 +1501,6 @@ Arch::Arch(ArchArgs args) : args(args) snprintf(buf, 32, "R%dC%d_%s_%s", row + 1, col + 1, srcid.c_str(this), destid.c_str(this)); IdString pipname = id(buf); DelayQuad delay = getWireTypeDelay(destid); - // local alias - auto local_alias = pairLookup(tile->aliases.get(), tile->num_aliases, srcid.index); - if (local_alias != nullptr) { - srcid = IdString(local_alias->src_id); - gsrcname = wireToGlobal(srcrow, srccol, db, srcid); - } // global alias srcid = IdString(pip.src_id); GlobalAliasPOD alias; From eac864ebdcdf7cf366e0dcbd5497e3c5cce3c479 Mon Sep 17 00:00:00 2001 From: gatecat Date: Thu, 9 Jun 2022 20:05:20 +0100 Subject: [PATCH 3/7] ecp5: Bind write_bitstream to Python Signed-off-by: gatecat --- ecp5/arch_pybindings.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ecp5/arch_pybindings.cc b/ecp5/arch_pybindings.cc index 593feb33..693d3199 100644 --- a/ecp5/arch_pybindings.cc +++ b/ecp5/arch_pybindings.cc @@ -23,6 +23,7 @@ #include "arch_pybindings.h" #include "nextpnr.h" #include "pybindings.h" +#include "bitstream.h" NEXTPNR_NAMESPACE_BEGIN @@ -69,6 +70,8 @@ void arch_wrap_python(py::module &m) WRAP_MAP_UPTR(m, CellMap, "IdCellMap"); WRAP_MAP_UPTR(m, NetMap, "IdNetMap"); WRAP_MAP(m, HierarchyMap, wrap_context, "HierarchyMap"); + + m.def("write_bitstream", &write_bitstream); } NEXTPNR_NAMESPACE_END From 8d063d38b148b1e7095a032ffc9cf957c2407f32 Mon Sep 17 00:00:00 2001 From: gatecat Date: Sun, 12 Jun 2022 07:59:36 +0100 Subject: [PATCH 4/7] clangformat Signed-off-by: gatecat --- ecp5/arch_pybindings.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ecp5/arch_pybindings.cc b/ecp5/arch_pybindings.cc index 693d3199..1621eda5 100644 --- a/ecp5/arch_pybindings.cc +++ b/ecp5/arch_pybindings.cc @@ -21,9 +21,9 @@ #ifndef NO_PYTHON #include "arch_pybindings.h" +#include "bitstream.h" #include "nextpnr.h" #include "pybindings.h" -#include "bitstream.h" NEXTPNR_NAMESPACE_BEGIN From b950f5cb6de869658564855eb64c46c50c4bc249 Mon Sep 17 00:00:00 2001 From: gatecat Date: Tue, 21 Jun 2022 12:35:13 +0100 Subject: [PATCH 5/7] Disable broken and failing interchange CI Signed-off-by: gatecat --- .../workflows/{interchange_ci.yml => interchange_ci.yml.disable} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/workflows/{interchange_ci.yml => interchange_ci.yml.disable} (100%) diff --git a/.github/workflows/interchange_ci.yml b/.github/workflows/interchange_ci.yml.disable similarity index 100% rename from .github/workflows/interchange_ci.yml rename to .github/workflows/interchange_ci.yml.disable From b502499a1e7cfc97bf8a69ffa0365c040dadf2fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chandler=20Kl=C3=BCser?= Date: Wed, 22 Jun 2022 21:03:04 -0300 Subject: [PATCH 6/7] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 14128b87..36ff9a8b 100644 --- a/README.md +++ b/README.md @@ -145,7 +145,8 @@ An example of how to use the generic flow is in [generic/examples](generic/examp The nextpnr GUI is not built by default, to reduce the number of dependencies for a standard headless build. To enable it, add `-DBUILD_GUI=ON` to the CMake command line and ensure that Qt5 and OpenGL are available: - - On Ubuntu, install `qt5-default` + - On Ubuntu 22.04 LTS, install `qtcreator qtbase5-dev qt5-qmake` + - On other Ubuntu versions, install `qt5-default` - For MSVC vcpkg, install `qt5-base` (32-bit) or `qt5-base:x64-windows` (64-bit) - For Homebrew, install `qt5` and add qt5 in path: `echo 'export PATH="/usr/local/opt/qt/bin:$PATH"' >> ~/.bash_profile` ` - this change is effective in next terminal session, so please re-open terminal window before building From 6122f172e3f15115cfb755ed702cc0438c341269 Mon Sep 17 00:00:00 2001 From: gatecat Date: Sat, 25 Jun 2022 15:56:16 +0100 Subject: [PATCH 7/7] ice40: Fix accidental creation of empty ports Signed-off-by: gatecat --- ice40/arch_place.cc | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/ice40/arch_place.cc b/ice40/arch_place.cc index 3b024d81..67ddf777 100644 --- a/ice40/arch_place.cc +++ b/ice40/arch_place.cc @@ -95,7 +95,7 @@ bool Arch::isBelLocationValid(BelId bel) const } return logic_cells_compatible(bel_cells.data(), num_cells); } else { - CellInfo *cell = getBoundBelCell(bel); + const CellInfo *cell = getBoundBelCell(bel); if (cell == nullptr) return true; else if (cell->type == id_SB_IO) { @@ -107,7 +107,7 @@ bool Arch::isBelLocationValid(BelId bel) const for (auto pin : getWireBelPins(wire)) { if (pin.pin == id_PLLOUT_A || pin.pin == id_PLLOUT_B) { // Is there a PLL there ? - auto pll_cell = getBoundBelCell(pin.bel); + const CellInfo *pll_cell = getBoundBelCell(pin.bel); if (pll_cell == nullptr) break; @@ -116,11 +116,11 @@ bool Arch::isBelLocationValid(BelId bel) const break; // Is that SB_IO used at an input ? - if ((cell->ports[id_D_IN_0].net == nullptr) && (cell->ports[id_D_IN_1].net == nullptr)) + if ((cell->getPort(id_D_IN_0) == nullptr) && (cell->getPort(id_D_IN_1) == nullptr)) break; // Are we perhaps a PAD INPUT Bel that can be placed here? - if (pll_cell->attrs[id_BEL_PAD_INPUT] == getBelName(bel).str(getCtx())) + if (str_or_default(pll_cell->attrs, id_BEL_PAD_INPUT, "") == getBelName(bel).str(getCtx())) return true; // Conflict @@ -144,7 +144,7 @@ bool Arch::isBelLocationValid(BelId bel) const } else { // Check LVDS IO is not placed at complement location BelId compBel = getBelByLocation(compLoc); - CellInfo *compCell = getBoundBelCell(compBel); + const CellInfo *compCell = getBoundBelCell(compBel); if (compCell && compCell->ioInfo.lvds) return false; @@ -161,10 +161,10 @@ bool Arch::isBelLocationValid(BelId bel) const _io_pintype_need_clk_en(cell->ioInfo.pintype), _io_pintype_need_clk_en(compCell->ioInfo.pintype), }; - NetInfo *nets[] = { - cell->ports[id_INPUT_CLK].net, compCell->ports[id_INPUT_CLK].net, - cell->ports[id_OUTPUT_CLK].net, compCell->ports[id_OUTPUT_CLK].net, - cell->ports[id_CLOCK_ENABLE].net, compCell->ports[id_CLOCK_ENABLE].net, + const NetInfo *nets[] = { + cell->getPort(id_INPUT_CLK), compCell->getPort(id_INPUT_CLK), + cell->getPort(id_OUTPUT_CLK), compCell->getPort(id_OUTPUT_CLK), + cell->getPort(id_CLOCK_ENABLE), compCell->getPort(id_CLOCK_ENABLE), }; for (int i = 0; i < 6; i++)