aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.cirrus/Dockerfile.ubuntu16.042
-rw-r--r--common/command.cc6
-rw-r--r--common/placer1.cc11
-rw-r--r--common/router1.cc4
-rw-r--r--common/timing.cc2
-rw-r--r--ecp5/arch.cc17
-rw-r--r--ecp5/arch.h11
-rw-r--r--ecp5/bitstream.cc29
-rw-r--r--ecp5/constids.inc100
-rw-r--r--gui/designwidget.cc8
-rw-r--r--gui/fpgaviewwidget.cc2
-rw-r--r--ice40/arch.cc15
-rw-r--r--ice40/pack.cc7
13 files changed, 199 insertions, 15 deletions
diff --git a/.cirrus/Dockerfile.ubuntu16.04 b/.cirrus/Dockerfile.ubuntu16.04
index 71a634bb..fb140d8d 100644
--- a/.cirrus/Dockerfile.ubuntu16.04
+++ b/.cirrus/Dockerfile.ubuntu16.04
@@ -46,7 +46,7 @@ RUN set -e -x ;\
cd /usr/local/src ;\
git clone --recursive https://github.com/SymbiFlow/prjtrellis.git ;\
cd prjtrellis ;\
- git reset --hard de035a6e5e5818804a66b9408f0ad381b10957db ;\
+ git reset --hard 46e95314be7f8850db80ad1ef6b3359b091fad93 ;\
cd libtrellis ;\
cmake -DCMAKE_INSTALL_PREFIX=/usr . ;\
make -j $(nproc) ;\
diff --git a/common/command.cc b/common/command.cc
index 6ba3442f..8f18f54d 100644
--- a/common/command.cc
+++ b/common/command.cc
@@ -124,6 +124,8 @@ po::options_description CommandHandler::getGeneralOptions()
general.add_options()("cstrweight", po::value<float>(), "placer weighting for relative constraint satisfaction");
general.add_options()("pack-only", "pack design only without placement or routing");
+ general.add_options()("ignore-loops", "ignore combinational loops in timing analysis");
+
general.add_options()("version,V", "show version");
general.add_options()("test", "check architecture database integrity");
general.add_options()("freq", po::value<double>(), "set target frequency for design in MHz");
@@ -172,6 +174,10 @@ void CommandHandler::setupContext(Context *ctx)
}
}
+ if (vm.count("ignore-loops")) {
+ settings->set("timing/ignoreLoops", true);
+ }
+
if (vm.count("cstrweight")) {
settings->set("placer1/constraintWeight", vm["cstrweight"].as<float>());
}
diff --git a/common/placer1.cc b/common/placer1.cc
index b42ef2ff..cec37847 100644
--- a/common/placer1.cc
+++ b/common/placer1.cc
@@ -24,6 +24,7 @@
#include "placer1.h"
#include <algorithm>
#include <boost/lexical_cast.hpp>
+#include <chrono>
#include <cmath>
#include <iostream>
#include <limits>
@@ -148,7 +149,7 @@ class SAPlacer
}
std::sort(autoplaced.begin(), autoplaced.end(), [](CellInfo *a, CellInfo *b) { return a->name < b->name; });
ctx->shuffle(autoplaced);
-
+ auto iplace_start = std::chrono::high_resolution_clock::now();
// Place cells randomly initially
log_info("Creating initial placement for remaining %d cells.\n", int(autoplaced.size()));
@@ -165,7 +166,9 @@ class SAPlacer
if (ctx->slack_redist_iter > 0)
assign_budget(ctx);
ctx->yield();
-
+ auto iplace_end = std::chrono::high_resolution_clock::now();
+ log_info("Initial placement time %.02fs\n", std::chrono::duration<float>(iplace_end - iplace_start).count());
+ auto saplace_start = std::chrono::high_resolution_clock::now();
log_info("Running simulated annealing placer.\n");
// Calculate metric after initial placement
@@ -283,6 +286,10 @@ class SAPlacer
// Let the UI show visualization updates.
ctx->yield();
}
+
+ auto saplace_end = std::chrono::high_resolution_clock::now();
+ log_info("SA placement time %.02fs\n", std::chrono::duration<float>(saplace_end - saplace_start).count());
+
// Final post-pacement validitiy check
ctx->yield();
for (auto bel : ctx->getBels()) {
diff --git a/common/router1.cc b/common/router1.cc
index cbc0df90..28a422c8 100644
--- a/common/router1.cc
+++ b/common/router1.cc
@@ -17,6 +17,7 @@
*
*/
+#include <chrono>
#include <cmath>
#include <queue>
@@ -752,6 +753,7 @@ bool router1(Context *ctx, const Router1Cfg &cfg)
log_break();
log_info("Routing..\n");
ctx->lock();
+ auto rstart = std::chrono::high_resolution_clock::now();
log_info("Setting up routing queue.\n");
@@ -803,7 +805,9 @@ bool router1(Context *ctx, const Router1Cfg &cfg)
router.arcs_with_ripup - last_arcs_with_ripup, router.arcs_without_ripup - last_arcs_without_ripup,
int(router.arc_queue.size()));
log_info("Routing complete.\n");
+ auto rend = std::chrono::high_resolution_clock::now();
ctx->yield();
+ log_info("Route time %.02fs\n", std::chrono::duration<float>(rend - rstart).count());
#ifndef NDEBUG
router.check();
diff --git a/common/timing.cc b/common/timing.cc
index 194a0e00..8a48b761 100644
--- a/common/timing.cc
+++ b/common/timing.cc
@@ -225,7 +225,7 @@ struct Timing
}
// Sanity check to ensure that all ports where fanins were recorded were indeed visited
- if (!port_fanin.empty()) {
+ if (!port_fanin.empty() && !bool_or_default(ctx->settings, ctx->id("timing/ignoreLoops"), false)) {
for (auto fanin : port_fanin) {
NetInfo *net = fanin.first->net;
if (net != nullptr) {
diff --git a/ecp5/arch.cc b/ecp5/arch.cc
index 380c0d7d..a2036033 100644
--- a/ecp5/arch.cc
+++ b/ecp5/arch.cc
@@ -681,6 +681,23 @@ TimingPortClass Arch::getPortTimingClass(const CellInfo *cell, IdString port, in
clockInfoCount = 1;
return (cell->ports.at(port).type == PORT_OUT) ? TMG_REGISTER_OUTPUT : TMG_REGISTER_INPUT;
}
+ } else if (cell->type == id_DTR || cell->type == id_USRMCLK || cell->type == id_SEDGA || cell->type == id_GSR ||
+ cell->type == id_JTAGG) {
+ return (cell->ports.at(port).type == PORT_OUT) ? TMG_STARTPOINT : TMG_ENDPOINT;
+ } else if (cell->type == id_OSCG) {
+ if (port == id_OSC)
+ return TMG_GEN_CLOCK;
+ else
+ return TMG_IGNORE;
+ } else if (cell->type == id_CLKDIVF) {
+ if (port == id_CLKI)
+ return TMG_CLOCK_INPUT;
+ else if (port == id_RST || port == id_ALIGNWD)
+ return TMG_ENDPOINT;
+ else if (port == id_CDIVX)
+ return TMG_GEN_CLOCK;
+ else
+ NPNR_ASSERT_FALSE("bad clkdiv port");
} else {
log_error("cell type '%s' is unsupported (instantiated as '%s')\n", cell->type.c_str(this),
cell->name.c_str(this));
diff --git a/ecp5/arch.h b/ecp5/arch.h
index a68673f4..4f2aaaa9 100644
--- a/ecp5/arch.h
+++ b/ecp5/arch.h
@@ -993,6 +993,17 @@ struct Arch : BaseCtx
NPNR_ASSERT_FALSE_STR("no tile at (" + std::to_string(col) + ", " + std::to_string(row) + ") with type in set");
}
+ std::string getTileByType(std::string type) const
+ {
+ for (int i = 0; i < chip_info->height * chip_info->width; i++) {
+ auto &tileloc = chip_info->tile_info[i];
+ for (int j = 0; j < tileloc.num_tiles; j++)
+ if (chip_info->tiletype_names[tileloc.tile_names[j].type_idx].get() == type)
+ return tileloc.tile_names[j].name.get();
+ }
+ NPNR_ASSERT_FALSE_STR("no with type " + type);
+ }
+
GlobalInfoPOD globalInfoAtLoc(Location loc);
// Apply LPF constraints to the context
diff --git a/ecp5/bitstream.cc b/ecp5/bitstream.cc
index 69398010..bec33f67 100644
--- a/ecp5/bitstream.cc
+++ b/ecp5/bitstream.cc
@@ -1120,6 +1120,35 @@ void write_bitstream(Context *ctx, std::string base_config_file, std::string tex
std::string tname = ctx->getTileByTypeAndLocation(loc.y + 1, loc.x, "BMID_0H");
cc.tiles[tname].add_enum("PCSCLKDIV" + std::to_string(loc.z),
str_or_default(ci->params, ctx->id("GSR"), "ENABLED"));
+ } else if (ci->type == id_DTR) {
+ cc.tiles[ctx->getTileByType("DTR")].add_enum("DTR.MODE", "DTR");
+ } else if (ci->type == id_OSCG) {
+ int div = int_or_default(ci->params, ctx->id("DIV"), 128);
+ if (div == 128)
+ div = 127;
+ cc.tiles[ctx->getTileByType("EFB0_PICB0")].add_enum("OSC.DIV", std::to_string(div));
+ cc.tiles[ctx->getTileByType("EFB1_PICB1")].add_enum("OSC.DIV", std::to_string(div));
+ cc.tiles[ctx->getTileByType("EFB1_PICB1")].add_enum("OSC.MODE", "OSCG");
+ cc.tiles[ctx->getTileByType("EFB1_PICB1")].add_enum("CCLK.MODE", "_NONE_");
+ } else if (ci->type == id_USRMCLK) {
+ cc.tiles[ctx->getTileByType("EFB3_PICB1")].add_enum("CCLK.MODE", "USRMCLK");
+ } else if (ci->type == id_GSR) {
+ cc.tiles[ctx->getTileByType("EFB0_PICB0")].add_enum(
+ "GSR.GSRMODE", str_or_default(ci->params, ctx->id("MODE"), "ACTIVE_HIGH"));
+ cc.tiles[ctx->getTileByType("VIQ_BUF")].add_enum("GSR.SYNCMODE",
+ str_or_default(ci->params, ctx->id("SYNCMODE"), "ASYNC"));
+ } else if (ci->type == id_JTAGG) {
+ cc.tiles[ctx->getTileByType("EFB0_PICB0")].add_enum("JTAG.ER1",
+ str_or_default(ci->params, ctx->id("ER1"), "ENABLED"));
+ cc.tiles[ctx->getTileByType("EFB0_PICB0")].add_enum("JTAG.ER2",
+ str_or_default(ci->params, ctx->id("ER2"), "ENABLED"));
+ } else if (ci->type == id_CLKDIVF) {
+ Loc loc = ctx->getBelLocation(ci->bel);
+ bool r = loc.x > 5;
+ std::string clkdiv = std::string("CLKDIV_") + (r ? "R" : "L") + std::to_string(loc.z);
+ std::string tile = ctx->getTileByType(std::string("ECLK_") + (r ? "R" : "L"));
+ cc.tiles[tile].add_enum(clkdiv + ".DIV", str_or_default(ci->params, ctx->id("DIV"), "2.0"));
+ cc.tiles[tile].add_enum(clkdiv + ".GSR", str_or_default(ci->params, ctx->id("GSR"), "DISABLED"));
} else {
NPNR_ASSERT_FALSE("unsupported cell type");
}
diff --git a/ecp5/constids.inc b/ecp5/constids.inc
index 202a7eb2..6ba453c7 100644
--- a/ecp5/constids.inc
+++ b/ecp5/constids.inc
@@ -1115,7 +1115,6 @@ X(SEL2)
X(SEL1)
X(SEL0)
X(CDIV1)
-X(CDIVX)
X(DP16KD_REGMODE_A_NOREG_REGMODE_B_NOREG)
X(DP16KD_REGMODE_A_NOREG_REGMODE_B_OUTREG)
@@ -1182,3 +1181,102 @@ X(RDPNTR2)
X(WRPNTR0)
X(WRPNTR1)
X(WRPNTR2)
+
+X(GSR)
+
+X(JTAGG)
+X(TCK)
+X(TMS)
+X(TDI)
+X(JTDO2)
+X(JTDO1)
+X(TDO)
+X(JTDI)
+X(JTCK)
+X(JRTI2)
+X(JRTI1)
+X(JSHIFT)
+X(JUPDATE)
+X(JRSTN)
+X(JCE2)
+X(JCE1)
+
+X(OSCG)
+X(OSC)
+X(SEDSTDBY)
+
+X(SEDGA)
+X(SEDENABLE)
+X(SEDSTART)
+X(SEDFRCERR)
+X(SEDDONE)
+X(SEDINPROG)
+X(SEDERR)
+
+X(DTR)
+X(STARTPULSE)
+X(DTROUT0)
+X(DTROUT1)
+X(DTROUT2)
+X(DTROUT3)
+X(DTROUT4)
+X(DTROUT5)
+X(DTROUT6)
+X(DTROUT7)
+
+X(USRMCLK)
+
+X(CLKDIVF)
+X(ALIGNWD)
+X(CDIVX)
+
+X(ECLKSYNCB)
+X(ECLKI)
+X(STOP)
+X(ECLKO)
+
+X(DLLDELD)
+X(A)
+X(DDRDEL)
+X(Z)
+
+X(DDRDLL)
+X(UDDCNTLN)
+X(FREEZE)
+X(DIVOSC)
+X(DCNTL0)
+X(DCNTL1)
+X(DCNTL2)
+X(DCNTL3)
+X(DCNTL4)
+X(DCNTL5)
+X(DCNTL6)
+X(DCNTL7)
+
+X(DQSBUFM)
+X(DQSI)
+X(READ1)
+X(READ0)
+X(READCLKSEL2)
+X(READCLKSEL1)
+X(READCLKSEL0)
+X(DYNDELAY0)
+X(DYNDELAY1)
+X(DYNDELAY2)
+X(DYNDELAY3)
+X(DYNDELAY4)
+X(DYNDELAY5)
+X(DYNDELAY6)
+X(DYNDELAY7)
+X(PAUSE)
+X(RDLOADN)
+X(RDMOVE)
+X(RDDIRECTION)
+X(WRLOADN)
+X(WRMOVE)
+X(WRDIRECTION)
+X(DATAVALID)
+X(BURSTDET)
+X(RDCFLAG)
+X(WRCFLAG)
+X(SCLK)
diff --git a/gui/designwidget.cc b/gui/designwidget.cc
index 235dd2cb..fc99cd14 100644
--- a/gui/designwidget.cc
+++ b/gui/designwidget.cc
@@ -706,8 +706,12 @@ void DesignWidget::onSelectionChanged(int num, const QItemSelection &, const QIt
addProperty(topItem, QVariant::String, "Type", ctx->getPipType(pip).c_str(ctx));
addProperty(topItem, QVariant::Bool, "Available", ctx->checkPipAvail(pip));
addProperty(topItem, QVariant::String, "Bound Net", ctx->nameOf(ctx->getBoundPipNet(pip)), ElementType::NET);
- addProperty(topItem, QVariant::String, "Conflicting Wire",
- ctx->getWireName(ctx->getConflictingPipWire(pip)).c_str(ctx), ElementType::WIRE);
+ if (ctx->getConflictingPipWire(pip) != WireId()) {
+ addProperty(topItem, QVariant::String, "Conflicting Wire",
+ ctx->getWireName(ctx->getConflictingPipWire(pip)).c_str(ctx), ElementType::WIRE);
+ } else {
+ addProperty(topItem, QVariant::String, "Conflicting Wire", "", ElementType::NONE);
+ }
addProperty(topItem, QVariant::String, "Conflicting Net", ctx->nameOf(ctx->getConflictingPipNet(pip)),
ElementType::NET);
addProperty(topItem, QVariant::String, "Src Wire", ctx->getWireName(ctx->getPipSrcWire(pip)).c_str(ctx),
diff --git a/gui/fpgaviewwidget.cc b/gui/fpgaviewwidget.cc
index 3fba6bff..0ad90527 100644
--- a/gui/fpgaviewwidget.cc
+++ b/gui/fpgaviewwidget.cc
@@ -102,7 +102,7 @@ void FPGAViewWidget::newContext(Context *ctx)
pokeRenderer();
}
-QSize FPGAViewWidget::minimumSizeHint() const { return QSize(640, 480); }
+QSize FPGAViewWidget::minimumSizeHint() const { return QSize(320, 200); }
QSize FPGAViewWidget::sizeHint() const { return QSize(640, 480); }
diff --git a/ice40/arch.cc b/ice40/arch.cc
index e674b4c9..f6084e72 100644
--- a/ice40/arch.cc
+++ b/ice40/arch.cc
@@ -594,26 +594,29 @@ std::vector<GroupId> Arch::getGroupGroups(GroupId group) const
bool Arch::getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay_t &budget) const
{
const auto &driver = net_info->driver;
- if (driver.port == id_COUT && sink.port == id_CIN) {
- if (driver.cell->constr_abs_z && driver.cell->constr_z < 7)
+ if (driver.port == id_COUT) {
+ NPNR_ASSERT(sink.port == id_CIN || sink.port == id_I3);
+ NPNR_ASSERT(driver.cell->constr_abs_z);
+ bool cin = sink.port == id_CIN;
+ bool same_y = driver.cell->constr_z < 7;
+ if (cin && same_y)
budget = 0;
else {
- NPNR_ASSERT(driver.cell->constr_z == 7);
switch (args.type) {
#ifndef ICE40_HX1K_ONLY
case ArchArgs::HX8K:
#endif
case ArchArgs::HX1K:
- budget = 190;
+ budget = cin ? 190 : (same_y ? 260 : 560);
break;
#ifndef ICE40_HX1K_ONLY
case ArchArgs::LP384:
case ArchArgs::LP1K:
case ArchArgs::LP8K:
- budget = 290;
+ budget = cin ? 290 : (same_y ? 380 : 670);
break;
case ArchArgs::UP5K:
- budget = 560;
+ budget = cin ? 560 : (same_y ? 660 : 1220);
break;
#endif
default:
diff --git a/ice40/pack.cc b/ice40/pack.cc
index a86083b6..6b3ddefc 100644
--- a/ice40/pack.cc
+++ b/ice40/pack.cc
@@ -1063,7 +1063,12 @@ static void pack_special(Context *ctx)
create_ice_cell(ctx, ctx->id("ICESTORM_PLL"), ci->name.str(ctx) + "_PLL");
packed->attrs[ctx->id("TYPE")] = ci->type.str(ctx);
packed_cells.insert(ci->name);
-
+ if (!is_sb_pll40_dual(ctx, ci)) {
+ // Remove second output, so a buffer isn't created for it, for these
+ // cell types with only one output
+ packed->ports.erase(ctx->id("PLLOUT_B"));
+ packed->ports.erase(ctx->id("PLLOUT_B_GLOBAL"));
+ }
for (auto attr : ci->attrs)
packed->attrs[attr.first] = attr.second;
for (auto param : ci->params)