diff options
-rw-r--r-- | .cirrus/Dockerfile.ubuntu16.04 | 2 | ||||
-rw-r--r-- | common/command.cc | 6 | ||||
-rw-r--r-- | common/placer1.cc | 11 | ||||
-rw-r--r-- | common/router1.cc | 4 | ||||
-rw-r--r-- | common/timing.cc | 2 | ||||
-rw-r--r-- | ecp5/arch.cc | 17 | ||||
-rw-r--r-- | ecp5/arch.h | 11 | ||||
-rw-r--r-- | ecp5/bitstream.cc | 29 | ||||
-rw-r--r-- | ecp5/constids.inc | 100 | ||||
-rw-r--r-- | gui/designwidget.cc | 8 | ||||
-rw-r--r-- | gui/fpgaviewwidget.cc | 2 | ||||
-rw-r--r-- | ice40/arch.cc | 15 | ||||
-rw-r--r-- | ice40/pack.cc | 7 |
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) |