From c27c96f4f0ec66d13bea7d7cdea25fbeb2e189b7 Mon Sep 17 00:00:00 2001 From: David Shah Date: Wed, 20 Jun 2018 20:12:23 +0200 Subject: place_sa: Improvements including supporting force and ordering consistency Signed-off-by: David Shah --- common/place_sa.cc | 24 ++++++++++++++++-------- ice40/pack.cc | 4 ++-- ice40/picorv32_arachne.sh | 4 ++-- 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/common/place_sa.cc b/common/place_sa.cc index 2b8b960b..7325c557 100644 --- a/common/place_sa.cc +++ b/common/place_sa.cc @@ -145,7 +145,7 @@ class SAPlacer curr_wirelength = 0; for (auto net : ctx->nets) { float wl = get_wirelength(net.second); - wirelengths[net.second] = wl; + wirelengths[net.first] = wl; curr_wirelength += wl; } @@ -221,9 +221,17 @@ class SAPlacer std::string cell_text = "no cell"; if (cell != IdString()) cell_text = std::string("cell '") + cell.str(ctx) + "'"; - log_error("post-placement validity check failed for Bel '%s' " - "(%s)", - ctx->getBelName(bel).c_str(ctx), cell_text.c_str()); + if (ctx->force) { + log_warning( + "post-placement validity check failed for Bel '%s' " + "(%s)\n", + ctx->getBelName(bel).c_str(ctx), cell_text.c_str()); + } else { + log_error( + "post-placement validity check failed for Bel '%s' " + "(%s)\n", + ctx->getBelName(bel).c_str(ctx), cell_text.c_str()); + } } } return true; @@ -328,7 +336,7 @@ class SAPlacer bool try_swap_position(CellInfo *cell, BelId newBel) { static std::unordered_set update; - static std::vector> new_lengths; + static std::vector> new_lengths; new_lengths.clear(); update.clear(); BelId oldBel = cell->bel; @@ -373,10 +381,10 @@ class SAPlacer // Recalculate wirelengths for all nets touched by the peturbation for (auto net : update) { - new_wirelength -= wirelengths.at(net); + new_wirelength -= wirelengths.at(net->name); float net_new_wl = get_wirelength(net); new_wirelength += net_new_wl; - new_lengths.push_back(std::make_pair(net, net_new_wl)); + new_lengths.push_back(std::make_pair(net->name, net_new_wl)); } delta = new_wirelength - curr_wirelength; n_move++; @@ -434,7 +442,7 @@ class SAPlacer } Context *ctx; - std::unordered_map wirelengths; + std::unordered_map wirelengths; float curr_wirelength = std::numeric_limits::infinity(); float temp = 1000; bool improved = false; diff --git a/ice40/pack.cc b/ice40/pack.cc index 19f1e7bc..853f510e 100644 --- a/ice40/pack.cc +++ b/ice40/pack.cc @@ -244,8 +244,8 @@ static void set_net_constant(const Context *ctx, NetInfo *orig, CellInfo *uc = user.cell; log_info("%s user %s\n", orig->name.c_str(ctx), uc->name.c_str(ctx)); - if (is_lut(ctx, uc) && (user.port.str(ctx).at(0) == 'I') && - !constval) { + if ((is_lut(ctx, uc) || is_lc(ctx, uc)) && + (user.port.str(ctx).at(0) == 'I') && !constval) { uc->ports[user.port].net = nullptr; } else { uc->ports[user.port].net = constnet; diff --git a/ice40/picorv32_arachne.sh b/ice40/picorv32_arachne.sh index 00cfe6a4..b3960fdc 100755 --- a/ice40/picorv32_arachne.sh +++ b/ice40/picorv32_arachne.sh @@ -3,7 +3,7 @@ set -ex rm -f picorv32.v wget https://raw.githubusercontent.com/cliffordwolf/picorv32/master/picorv32.v yosys -p 'synth_ice40 -nocarry -blif picorv32.blif -top top' picorv32.v picorv32_top.v -arachne-pnr -d 8k --post-place-blif picorv32_place.blif picorv32.blif +arachne-pnr -d 8k --post-place-blif picorv32_place.blif picorv32.blif -o picorv32_arachne_all.asc yosys -p "read_blif -wideports picorv32_place.blif; read_verilog -lib +/ice40/cells_sim.v; write_json picorv32_place.json" ./transform_arachne_loc.py picorv32_place.json > picorv32_place_nx.json -../nextpnr-ice40 --hx8k --asc picorv32.asc --json picorv32_place_nx.json +../nextpnr-ice40 --hx8k --asc picorv32_ar_placed.asc --json picorv32_place_nx.json --force -- cgit v1.2.3 From 1df8a8b44091246acc8929cc803578c6d705eee1 Mon Sep 17 00:00:00 2001 From: David Shah Date: Wed, 20 Jun 2018 20:25:48 +0200 Subject: place_sa: Reduce effect of rounding errors Signed-off-by: David Shah --- common/place_sa.cc | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/common/place_sa.cc b/common/place_sa.cc index 7325c557..4a2fc86e 100644 --- a/common/place_sa.cc +++ b/common/place_sa.cc @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include @@ -213,6 +212,15 @@ class SAPlacer temp *= 0.8; } } + + // Recalculate total wirelength entirely to avoid rounding errors + // accumulating over time + curr_wirelength = 0; + for (auto net : ctx->nets) { + float wl = get_wirelength(net.second); + wirelengths[net.first] = wl; + curr_wirelength += wl; + } } // Final post-pacement validitiy check for (auto bel : ctx->getBels()) { -- cgit v1.2.3 From e526a4115bddab74441ac9dbdb4aa56ff6f6bf3f Mon Sep 17 00:00:00 2001 From: David Shah Date: Thu, 21 Jun 2018 10:45:18 +0200 Subject: place_sa: Use int64_t for "wirelength" metric Signed-off-by: David Shah --- common/place_sa.cc | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/common/place_sa.cc b/common/place_sa.cc index 4a2fc86e..39855e47 100644 --- a/common/place_sa.cc +++ b/common/place_sa.cc @@ -41,6 +41,8 @@ NEXTPNR_NAMESPACE_BEGIN +typedef int64_t wirelen_t; + class SAPlacer { public: @@ -143,7 +145,7 @@ class SAPlacer // Calculate wirelength after initial placement curr_wirelength = 0; for (auto net : ctx->nets) { - float wl = get_wirelength(net.second); + wirelen_t wl = get_wirelength(net.second); wirelengths[net.first] = wl; curr_wirelength += wl; } @@ -159,7 +161,7 @@ class SAPlacer if (iter % 5 == 0 || iter == 1) log_info(" at iteration #%d: temp = %f, wire length = %f\n", - iter, temp, curr_wirelength); + iter, temp, double(curr_wirelength)); for (int m = 0; m < 15; ++m) { // Loop through all automatically placed cells @@ -182,7 +184,7 @@ class SAPlacer if (iter % 5 != 0) log_info( " at iteration #%d: temp = %f, wire length = %f\n", - iter, temp, curr_wirelength); + iter, temp, double(curr_wirelength)); break; } @@ -217,7 +219,7 @@ class SAPlacer // accumulating over time curr_wirelength = 0; for (auto net : ctx->nets) { - float wl = get_wirelength(net.second); + wirelen_t wl = get_wirelength(net.second); wirelengths[net.first] = wl; curr_wirelength += wl; } @@ -304,9 +306,9 @@ class SAPlacer } // Get the total estimated wirelength for a net - float get_wirelength(NetInfo *net) + wirelen_t get_wirelength(NetInfo *net) { - float wirelength = 0; + wirelen_t wirelength = 0; int driver_x, driver_y; bool driver_gb; CellInfo *driver_cell = net->driver.cell; @@ -331,10 +333,11 @@ class SAPlacer // wirelength += std::abs(load_x - driver_x) + std::abs(load_y - // driver_y); delay_t raw_wl = ctx->estimateDelay(drv_wire, user_wire); - wirelength += pow(1.3, (ctx->getDelayNS(raw_wl) - - ctx->getDelayNS(load.budget)) / - 10) + - ctx->getDelayNS(raw_wl); + wirelength += wirelen_t((pow(1.3, (ctx->getDelayNS(raw_wl) - + ctx->getDelayNS(load.budget)) / + 10) + + ctx->getDelayNS(raw_wl)) * + 10); // wirelength += pow(ctx->estimateDelay(drv_wire, user_wire), 2.0); } return wirelength; @@ -344,13 +347,13 @@ class SAPlacer bool try_swap_position(CellInfo *cell, BelId newBel) { static std::unordered_set update; - static std::vector> new_lengths; + static std::vector> new_lengths; new_lengths.clear(); update.clear(); BelId oldBel = cell->bel; IdString other = ctx->getBelCell(newBel, true); CellInfo *other_cell = nullptr; - float new_wirelength = 0, delta; + wirelen_t new_wirelength = 0, delta; ctx->unbindBel(oldBel); if (other != IdString()) { other_cell = ctx->cells[other]; @@ -390,7 +393,7 @@ class SAPlacer // Recalculate wirelengths for all nets touched by the peturbation for (auto net : update) { new_wirelength -= wirelengths.at(net->name); - float net_new_wl = get_wirelength(net); + wirelen_t net_new_wl = get_wirelength(net); new_wirelength += net_new_wl; new_lengths.push_back(std::make_pair(net->name, net_new_wl)); } @@ -400,7 +403,7 @@ class SAPlacer if (delta < 0 || (temp > 1e-6 && (ctx->rng() / float(0x3fffffff)) <= std::exp(-delta / temp))) { n_accept++; - if (delta < 0) + if (delta < 2) improved = true; } else { if (other != IdString()) @@ -450,8 +453,8 @@ class SAPlacer } Context *ctx; - std::unordered_map wirelengths; - float curr_wirelength = std::numeric_limits::infinity(); + std::unordered_map wirelengths; + wirelen_t curr_wirelength = std::numeric_limits::max(); float temp = 1000; bool improved = false; int n_move, n_accept; -- cgit v1.2.3 From 9e28e45bd5e1f322f11f4759e8174d861df2eb2c Mon Sep 17 00:00:00 2001 From: David Shah Date: Thu, 21 Jun 2018 11:45:58 +0200 Subject: place_sa: Make the heuristic closer to arachne, seems to improve routability Signed-off-by: David Shah --- common/place_sa.cc | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/common/place_sa.cc b/common/place_sa.cc index 39855e47..e792474d 100644 --- a/common/place_sa.cc +++ b/common/place_sa.cc @@ -321,25 +321,33 @@ class SAPlacer driver_cell->bel, ctx->portPinFromId(net->driver.port)); if (driver_gb) return 0; + float worst_slack = 1000; + int xmin = driver_x, xmax = driver_x, ymin = driver_y, ymax = driver_y; for (auto load : net->users) { if (load.cell == nullptr) continue; CellInfo *load_cell = load.cell; if (load_cell->bel == BelId()) continue; - // ctx->estimatePosition(load_cell->bel, load_x, load_y, load_gb); + WireId user_wire = ctx->getWireBelPin( load_cell->bel, ctx->portPinFromId(load.port)); - // wirelength += std::abs(load_x - driver_x) + std::abs(load_y - - // driver_y); delay_t raw_wl = ctx->estimateDelay(drv_wire, user_wire); - wirelength += wirelen_t((pow(1.3, (ctx->getDelayNS(raw_wl) - - ctx->getDelayNS(load.budget)) / - 10) + - ctx->getDelayNS(raw_wl)) * - 10); - // wirelength += pow(ctx->estimateDelay(drv_wire, user_wire), 2.0); + float slack = + ctx->getDelayNS(raw_wl) - ctx->getDelayNS(load.budget); + worst_slack = std::min(slack, worst_slack); + int load_x, load_y; + bool load_gb; + ctx->estimatePosition(load_cell->bel, load_x, load_y, load_gb); + if (load_gb) + continue; + xmin = std::min(xmin, load_x); + ymin = std::min(ymin, load_y); + xmax = std::max(xmax, load_x); + ymax = std::max(ymax, load_y); } + wirelength = wirelen_t((((ymax - ymin) + (xmax - xmin)) * + (1.0 + std::exp(-worst_slack / 5)))); return wirelength; } @@ -400,8 +408,9 @@ class SAPlacer delta = new_wirelength - curr_wirelength; n_move++; // SA acceptance criterea - if (delta < 0 || (temp > 1e-6 && (ctx->rng() / float(0x3fffffff)) <= - std::exp(-delta / temp))) { + if (delta < 0 || + (temp > 1e-6 && (ctx->rng() / float(0x3fffffff)) <= + std::exp(-(delta / 2) / temp))) { n_accept++; if (delta < 2) improved = true; -- cgit v1.2.3 From 56ed679f831f703ad2f170713e0b127a97da40b3 Mon Sep 17 00:00:00 2001 From: David Shah Date: Thu, 21 Jun 2018 11:59:20 +0200 Subject: Add frequency setting and fix slack calculation Signed-off-by: David Shah --- common/place_sa.cc | 2 +- common/timing.cc | 11 +++++------ ice40/main.cc | 7 ++++++- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/common/place_sa.cc b/common/place_sa.cc index e792474d..2f8fb122 100644 --- a/common/place_sa.cc +++ b/common/place_sa.cc @@ -334,7 +334,7 @@ class SAPlacer load_cell->bel, ctx->portPinFromId(load.port)); delay_t raw_wl = ctx->estimateDelay(drv_wire, user_wire); float slack = - ctx->getDelayNS(raw_wl) - ctx->getDelayNS(load.budget); + ctx->getDelayNS(load.budget) - ctx->getDelayNS(raw_wl); worst_slack = std::min(slack, worst_slack); int load_x, load_y; bool load_gb; diff --git a/common/timing.cc b/common/timing.cc index 8da26077..a7b37f9d 100644 --- a/common/timing.cc +++ b/common/timing.cc @@ -101,7 +101,6 @@ void assign_budget(Context *ctx, float default_clock) } } } - const bool debug = true; // Post-allocation check for (auto net : ctx->nets) { @@ -111,11 +110,11 @@ void assign_budget(Context *ctx, float default_clock) "timing budget of %fns\n", user.cell->name.c_str(ctx), user.port.c_str(ctx), net.first.c_str(ctx), ctx->getDelayNS(user.budget)); - if (debug) - log_warning("port %s.%s, connected to net '%s', has " - "timing budget of %fns\n", - user.cell->name.c_str(ctx), user.port.c_str(ctx), - net.first.c_str(ctx), ctx->getDelayNS(user.budget)); + if (ctx->verbose) + log_info("port %s.%s, connected to net '%s', has " + "timing budget of %fns\n", + user.cell->name.c_str(ctx), user.port.c_str(ctx), + net.first.c_str(ctx), ctx->getDelayNS(user.budget)); } } } diff --git a/ice40/main.cc b/ice40/main.cc index 8143a902..fcf112e6 100644 --- a/ice40/main.cc +++ b/ice40/main.cc @@ -93,6 +93,8 @@ int main(int argc, char *argv[]) options.add_options()("hx1k", "set device type to iCE40HX1K"); options.add_options()("hx8k", "set device type to iCE40HX8K"); options.add_options()("up5k", "set device type to iCE40UP5K"); + options.add_options()("freq", po::value(), + "set target frequency for design in MHz"); options.add_options()("package", po::value(), "set device package"); po::positional_options_description pos; @@ -286,7 +288,10 @@ int main(int argc, char *argv[]) if (!pack_design(&ctx) && !ctx.force) log_error("Packing design failed.\n"); - assign_budget(&ctx, 50e6); + double freq = 50e6; + if (vm.count("freq")) + freq = vm["freq"].as() * 1e6; + assign_budget(&ctx, freq); print_utilisation(&ctx); if (!vm.count("pack-only")) { -- cgit v1.2.3 From 9c03909ebaec8157824a9cb13eeea774d29b35e1 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Thu, 21 Jun 2018 13:41:16 +0200 Subject: Make arch specific main window --- CMakeLists.txt | 4 +- common/emb.cc | 138 +++++++++++++++++++++++++++++++++++++++++++++ common/emb.h | 20 +++++++ gui/CMakeLists.txt | 3 +- gui/basewindow.cc | 138 +++++++++++++++++++++++++++++++++++++++++++++ gui/basewindow.h | 45 +++++++++++++++ gui/dummy/mainwindow.cc | 19 +++++++ gui/dummy/mainwindow.h | 21 +++++++ gui/emb.cc | 138 --------------------------------------------- gui/emb.h | 20 ------- gui/fpgaviewwidget.cc | 4 +- gui/ice40/mainwindow.cc | 29 ++++++++++ gui/ice40/mainwindow.h | 21 +++++++ gui/mainwindow.cc | 145 ------------------------------------------------ gui/mainwindow.h | 36 ------------ 15 files changed, 437 insertions(+), 344 deletions(-) create mode 100644 common/emb.cc create mode 100644 common/emb.h create mode 100644 gui/basewindow.cc create mode 100644 gui/basewindow.h create mode 100644 gui/dummy/mainwindow.cc create mode 100644 gui/dummy/mainwindow.h delete mode 100644 gui/emb.cc delete mode 100644 gui/emb.h create mode 100644 gui/ice40/mainwindow.cc create mode 100644 gui/ice40/mainwindow.h delete mode 100644 gui/mainwindow.cc delete mode 100644 gui/mainwindow.h diff --git a/CMakeLists.txt b/CMakeLists.txt index ac58f169..8a64369f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -79,7 +79,7 @@ if (NOT Boost_PYTHON_FOUND ) message( FATAL_ERROR "No version of Boost::Python 3.x could be found.") endif () -include_directories(common/ gui/ frontend/json ${Boost_INCLUDE_DIRS} ${PYTHON_INCLUDE_DIRS} 3rdparty/QtPropertyBrowser/src) +include_directories(common/ frontend/json ${Boost_INCLUDE_DIRS} ${PYTHON_INCLUDE_DIRS}) aux_source_directory(common/ COMMON_SRC_FILES) aux_source_directory(frontend/json/ JSON_PARSER_FILES) set(COMMON_FILES ${COMMON_SRC_FILES} ${JSON_PARSER_FILES}) @@ -115,7 +115,7 @@ foreach (family ${FAMILIES}) include(${family}/family.cmake) foreach (target ${family_targets}) # Include family-specific source files to all family targets and set defines appropriately - target_include_directories(${target} PRIVATE ${family}/ generated/) + target_include_directories(${target} PRIVATE ${family}/ generated/ gui/${family}/) target_compile_definitions(${target} PRIVATE NEXTPNR_NAMESPACE=nextpnr_${family} ARCH_${ufamily} ARCHNAME=${family} QT_NO_KEYWORDS) target_link_libraries(${target} LINK_PUBLIC gui_${family} ${Boost_LIBRARIES} ${PYTHON_LIBRARIES} ${GUI_LIBRARY_FILES_${ufamily}}) endforeach (target) diff --git a/common/emb.cc b/common/emb.cc new file mode 100644 index 00000000..2e3379d5 --- /dev/null +++ b/common/emb.cc @@ -0,0 +1,138 @@ +// +// Copyright (C) 2011 Mateusz Loskot +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// Blog article: http://mateusz.loskot.net/?p=2819 + +#include "emb.h" +#include +#include +#include +#include + +namespace emb { +struct Stdout +{ + PyObject_HEAD stdout_write_type write; +}; + +PyObject *Stdout_write(PyObject *self, PyObject *args) +{ + std::size_t written(0); + Stdout *selfimpl = reinterpret_cast(self); + if (selfimpl->write) { + char *data; + if (!PyArg_ParseTuple(args, "s", &data)) + return 0; + + std::string str(data); + selfimpl->write(str); + written = str.size(); + } + return PyLong_FromSize_t(written); +} + +PyObject *Stdout_flush(PyObject *self, PyObject *args) +{ + // no-op + return Py_BuildValue(""); +} + +PyMethodDef Stdout_methods[] = { + {"write", Stdout_write, METH_VARARGS, "sys.stdout.write"}, + {"flush", Stdout_flush, METH_VARARGS, "sys.stdout.write"}, + {0, 0, 0, 0} // sentinel +}; + +PyTypeObject StdoutType = { + PyVarObject_HEAD_INIT(0, 0) "emb.StdoutType", /* tp_name */ + sizeof(Stdout), /* tp_basicsize */ + 0, /* tp_itemsize */ + 0, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_reserved */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + "emb.Stdout objects", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + Stdout_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ +}; + +PyModuleDef embmodule = { + PyModuleDef_HEAD_INIT, "emb", 0, -1, 0, +}; + +// Internal state +PyObject *g_stdout; +PyObject *g_stdout_saved; + +PyMODINIT_FUNC PyInit_emb(void) +{ + g_stdout = 0; + g_stdout_saved = 0; + + StdoutType.tp_new = PyType_GenericNew; + if (PyType_Ready(&StdoutType) < 0) + return 0; + + PyObject *m = PyModule_Create(&embmodule); + if (m) { + Py_INCREF(&StdoutType); + PyModule_AddObject(m, "Stdout", + reinterpret_cast(&StdoutType)); + } + return m; +} + +void set_stdout(stdout_write_type write) +{ + if (!g_stdout) { + g_stdout_saved = PySys_GetObject("stdout"); // borrowed + g_stdout = StdoutType.tp_new(&StdoutType, 0, 0); + } + + Stdout *impl = reinterpret_cast(g_stdout); + impl->write = write; + PySys_SetObject("stdout", g_stdout); +} + +void reset_stdout() +{ + if (g_stdout_saved) + PySys_SetObject("stdout", g_stdout_saved); + + Py_XDECREF(g_stdout); + g_stdout = 0; +} + +void append_inittab() { PyImport_AppendInittab("emb", emb::PyInit_emb); } + +} // namespace emb diff --git a/common/emb.h b/common/emb.h new file mode 100644 index 00000000..3daa7ca3 --- /dev/null +++ b/common/emb.h @@ -0,0 +1,20 @@ +// +// Copyright (C) 2011 Mateusz Loskot +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// +// Blog article: http://mateusz.loskot.net/?p=2819 + +#include +#include +#include + +namespace emb { +typedef std::function stdout_write_type; + +void set_stdout(stdout_write_type write); +void reset_stdout(); + +void append_inittab(); +} // namespace emb diff --git a/gui/CMakeLists.txt b/gui/CMakeLists.txt index 5db86a9b..b4dcde11 100644 --- a/gui/CMakeLists.txt +++ b/gui/CMakeLists.txt @@ -2,6 +2,7 @@ set(CMAKE_AUTOMOC ON) set(CMAKE_INCLUDE_CURRENT_DIR ON) aux_source_directory(. GUI_SOURCE_FILES) +aux_source_directory(${family}/ GUI_SOURCE_FILES) set(_RESOURCES nextpnr.qrc) qt5_add_resources(GUI_RESOURCE_FILES ${_RESOURCES}) @@ -10,6 +11,6 @@ set(GUI_LIBRARY_FILES_${ufamily} Qt5::Widgets Qt5::OpenGL ${OPENGL_LIBRARIES} Qt add_library(gui_${family} STATIC ${GUI_SOURCE_FILES} ${GUI_RESOURCE_FILES}) -target_include_directories(gui_${family} PRIVATE ../${family}/) +target_include_directories(gui_${family} PRIVATE ../${family} ${family} ../3rdparty/QtPropertyBrowser/src) target_compile_definitions(gui_${family} PRIVATE NEXTPNR_NAMESPACE=nextpnr_${family} ARCH_${ufamily} ARCHNAME=${family} QT_NO_KEYWORDS) target_link_libraries(gui_${family} Qt5::Widgets) diff --git a/gui/basewindow.cc b/gui/basewindow.cc new file mode 100644 index 00000000..cbf0faae --- /dev/null +++ b/gui/basewindow.cc @@ -0,0 +1,138 @@ +#include "mainwindow.h" +#include +#include +#include +#include +#include +#include +#include "designwidget.h" +#include "fpgaviewwidget.h" +#include "jsonparse.h" +#include "log.h" +#include "pythontab.h" +//#include "pack.h" +//#include "pcf.h" +#include "place_sa.h" +#include "route.h" +//#include "bitstream.h" +#include "design_utils.h" + +BaseMainWindow::BaseMainWindow(Context *_ctx, QWidget *parent) + : QMainWindow(parent), ctx(_ctx) +{ + Q_INIT_RESOURCE(nextpnr); + + log_files.clear(); + log_streams.clear(); + log_write_function = [this](std::string text) { info->info(text); }; + + setObjectName(QStringLiteral("BaseMainWindow")); + resize(1024, 768); + + createMenusAndBars(); + + QWidget *centralWidget = new QWidget(this); + + QGridLayout *gridLayout = new QGridLayout(centralWidget); + gridLayout->setSpacing(6); + gridLayout->setContentsMargins(11, 11, 11, 11); + + QSplitter *splitter_h = new QSplitter(Qt::Horizontal, centralWidget); + QSplitter *splitter_v = new QSplitter(Qt::Vertical, splitter_h); + splitter_h->addWidget(splitter_v); + + gridLayout->addWidget(splitter_h, 0, 0, 1, 1); + + setCentralWidget(centralWidget); + + DesignWidget *designview = new DesignWidget(ctx); + designview->setMinimumWidth(300); + designview->setMaximumWidth(300); + splitter_h->addWidget(designview); + + connect(designview, SIGNAL(info(std::string)), this, + SLOT(writeInfo(std::string))); + + tabWidget = new QTabWidget(); + tabWidget->addTab(new PythonTab(), "Python"); + info = new InfoTab(); + tabWidget->addTab(info, "Info"); + splitter_v->addWidget(new FPGAViewWidget()); + splitter_v->addWidget(tabWidget); +} + +BaseMainWindow::~BaseMainWindow() {} + +void BaseMainWindow::writeInfo(std::string text) { info->info(text); } + +void BaseMainWindow::createMenusAndBars() +{ + QAction *actionOpen = new QAction("Open", this); + QIcon icon1; + icon1.addFile(QStringLiteral(":/icons/resources/open.png")); + actionOpen->setIcon(icon1); + actionOpen->setShortcuts(QKeySequence::Open); + actionOpen->setStatusTip("Open an existing JSON file"); + connect(actionOpen, SIGNAL(triggered()), this, SLOT(open())); + + QAction *actionSave = new QAction("Save", this); + QIcon icon2; + icon2.addFile(QStringLiteral(":/icons/resources/save.png")); + actionSave->setIcon(icon2); + actionSave->setShortcuts(QKeySequence::Save); + actionSave->setStatusTip("Save the ASC to disk"); + connect(actionSave, SIGNAL(triggered()), this, SLOT(save())); + actionSave->setEnabled(false); + + QAction *actionExit = new QAction("Exit", this); + QIcon icon3; + icon3.addFile(QStringLiteral(":/icons/resources/exit.png")); + actionExit->setIcon(icon3); + actionExit->setShortcuts(QKeySequence::Quit); + actionExit->setStatusTip("Exit the application"); + connect(actionExit, SIGNAL(triggered()), this, SLOT(close())); + + QAction *actionAbout = new QAction("About", this); + + menuBar = new QMenuBar(); + menuBar->setGeometry(QRect(0, 0, 1024, 27)); + QMenu *menu_File = new QMenu("&File", menuBar); + QMenu *menu_Help = new QMenu("&Help", menuBar); + menuBar->addAction(menu_File->menuAction()); + menuBar->addAction(menu_Help->menuAction()); + setMenuBar(menuBar); + + mainToolBar = new QToolBar(); + addToolBar(Qt::TopToolBarArea, mainToolBar); + + statusBar = new QStatusBar(); + setStatusBar(statusBar); + + menu_File->addAction(actionOpen); + menu_File->addAction(actionSave); + menu_File->addSeparator(); + menu_File->addAction(actionExit); + menu_Help->addAction(actionAbout); + + mainToolBar->addAction(actionOpen); + mainToolBar->addAction(actionSave); +} + +void BaseMainWindow::open() +{ + QString fileName = QFileDialog::getOpenFileName(this, QString(), QString(), + QString("*.json")); + if (!fileName.isEmpty()) { + tabWidget->setCurrentWidget(info); + + std::string fn = fileName.toStdString(); + std::istream *f = new std::ifstream(fn); + + parse_json_file(f, fn, ctx); + + // pack_design(ctx); + print_utilisation(ctx); + } +} + +bool BaseMainWindow::save() { return false; } diff --git a/gui/basewindow.h b/gui/basewindow.h new file mode 100644 index 00000000..52efd6b1 --- /dev/null +++ b/gui/basewindow.h @@ -0,0 +1,45 @@ +#ifndef BASEMAINWINDOW_H +#define BASEMAINWINDOW_H + +#include "infotab.h" +#include "nextpnr.h" + +#include +#include +#include +#include +#include +#include + + +// FIXME +USING_NEXTPNR_NAMESPACE + +class BaseMainWindow : public QMainWindow +{ + Q_OBJECT + + public: + explicit BaseMainWindow(Context *ctx, QWidget *parent = 0); + ~BaseMainWindow(); + Context *getContext() { return ctx; } + + protected: + void createMenusAndBars(); + + protected Q_SLOTS: + void writeInfo(std::string text); + void open(); + bool save(); + + protected: + Context *ctx; + QTabWidget *tabWidget; + InfoTab *info; + + QMenuBar *menuBar; + QToolBar *mainToolBar; + QStatusBar *statusBar; +}; + +#endif // BASEMAINWINDOW_H diff --git a/gui/dummy/mainwindow.cc b/gui/dummy/mainwindow.cc new file mode 100644 index 00000000..dad73d7e --- /dev/null +++ b/gui/dummy/mainwindow.cc @@ -0,0 +1,19 @@ +#include "mainwindow.h" + +MainWindow::MainWindow(Context *_ctx, QWidget *parent) + : BaseMainWindow(_ctx, parent) +{ + std::string title = "nextpnr-dummy - " + ctx->getChipName(); + setWindowTitle(title.c_str()); + + createMenu(); +} + +MainWindow::~MainWindow() {} + +void MainWindow::createMenu() +{ + QMenu *menu_Custom = new QMenu("&Dummy", menuBar); + menuBar->addAction(menu_Custom->menuAction()); + +} diff --git a/gui/dummy/mainwindow.h b/gui/dummy/mainwindow.h new file mode 100644 index 00000000..e9c8ff77 --- /dev/null +++ b/gui/dummy/mainwindow.h @@ -0,0 +1,21 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include "../basewindow.h" + +// FIXME +USING_NEXTPNR_NAMESPACE + +class MainWindow : public BaseMainWindow +{ + Q_OBJECT + + public: + explicit MainWindow(Context *ctx, QWidget *parent = 0); + ~MainWindow(); + + public: + void createMenu(); +}; + +#endif // MAINWINDOW_H diff --git a/gui/emb.cc b/gui/emb.cc deleted file mode 100644 index 2e3379d5..00000000 --- a/gui/emb.cc +++ /dev/null @@ -1,138 +0,0 @@ -// -// Copyright (C) 2011 Mateusz Loskot -// Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) -// -// Blog article: http://mateusz.loskot.net/?p=2819 - -#include "emb.h" -#include -#include -#include -#include - -namespace emb { -struct Stdout -{ - PyObject_HEAD stdout_write_type write; -}; - -PyObject *Stdout_write(PyObject *self, PyObject *args) -{ - std::size_t written(0); - Stdout *selfimpl = reinterpret_cast(self); - if (selfimpl->write) { - char *data; - if (!PyArg_ParseTuple(args, "s", &data)) - return 0; - - std::string str(data); - selfimpl->write(str); - written = str.size(); - } - return PyLong_FromSize_t(written); -} - -PyObject *Stdout_flush(PyObject *self, PyObject *args) -{ - // no-op - return Py_BuildValue(""); -} - -PyMethodDef Stdout_methods[] = { - {"write", Stdout_write, METH_VARARGS, "sys.stdout.write"}, - {"flush", Stdout_flush, METH_VARARGS, "sys.stdout.write"}, - {0, 0, 0, 0} // sentinel -}; - -PyTypeObject StdoutType = { - PyVarObject_HEAD_INIT(0, 0) "emb.StdoutType", /* tp_name */ - sizeof(Stdout), /* tp_basicsize */ - 0, /* tp_itemsize */ - 0, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_reserved */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - "emb.Stdout objects", /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - Stdout_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - 0, /* tp_new */ -}; - -PyModuleDef embmodule = { - PyModuleDef_HEAD_INIT, "emb", 0, -1, 0, -}; - -// Internal state -PyObject *g_stdout; -PyObject *g_stdout_saved; - -PyMODINIT_FUNC PyInit_emb(void) -{ - g_stdout = 0; - g_stdout_saved = 0; - - StdoutType.tp_new = PyType_GenericNew; - if (PyType_Ready(&StdoutType) < 0) - return 0; - - PyObject *m = PyModule_Create(&embmodule); - if (m) { - Py_INCREF(&StdoutType); - PyModule_AddObject(m, "Stdout", - reinterpret_cast(&StdoutType)); - } - return m; -} - -void set_stdout(stdout_write_type write) -{ - if (!g_stdout) { - g_stdout_saved = PySys_GetObject("stdout"); // borrowed - g_stdout = StdoutType.tp_new(&StdoutType, 0, 0); - } - - Stdout *impl = reinterpret_cast(g_stdout); - impl->write = write; - PySys_SetObject("stdout", g_stdout); -} - -void reset_stdout() -{ - if (g_stdout_saved) - PySys_SetObject("stdout", g_stdout_saved); - - Py_XDECREF(g_stdout); - g_stdout = 0; -} - -void append_inittab() { PyImport_AppendInittab("emb", emb::PyInit_emb); } - -} // namespace emb diff --git a/gui/emb.h b/gui/emb.h deleted file mode 100644 index 3daa7ca3..00000000 --- a/gui/emb.h +++ /dev/null @@ -1,20 +0,0 @@ -// -// Copyright (C) 2011 Mateusz Loskot -// Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) -// -// Blog article: http://mateusz.loskot.net/?p=2819 - -#include -#include -#include - -namespace emb { -typedef std::function stdout_write_type; - -void set_stdout(stdout_write_type write); -void reset_stdout(); - -void append_inittab(); -} // namespace emb diff --git a/gui/fpgaviewwidget.cc b/gui/fpgaviewwidget.cc index 000b4cf0..6b7e7787 100644 --- a/gui/fpgaviewwidget.cc +++ b/gui/fpgaviewwidget.cc @@ -9,14 +9,14 @@ FPGAViewWidget::FPGAViewWidget(QWidget *parent) : QOpenGLWidget(parent), m_xMove(0), m_yMove(0), m_zDistance(1.0) { - ctx = qobject_cast(getMainWindow())->getContext(); + ctx = qobject_cast(getMainWindow())->getContext(); } QMainWindow *FPGAViewWidget::getMainWindow() { QWidgetList widgets = qApp->topLevelWidgets(); for (QWidgetList::iterator i = widgets.begin(); i != widgets.end(); ++i) - if ((*i)->objectName() == "MainWindow") + if ((*i)->objectName() == "BaseMainWindow") return (QMainWindow *)(*i); return NULL; } diff --git a/gui/ice40/mainwindow.cc b/gui/ice40/mainwindow.cc new file mode 100644 index 00000000..4f53c551 --- /dev/null +++ b/gui/ice40/mainwindow.cc @@ -0,0 +1,29 @@ +#include "mainwindow.h" +#include +#include +#include "jsonparse.h" +#include "log.h" +#include "pack.h" +#include "pcf.h" +#include "place_sa.h" +#include "route.h" +#include "bitstream.h" +#include "design_utils.h" + +MainWindow::MainWindow(Context *_ctx, QWidget *parent) + : BaseMainWindow(_ctx, parent) +{ + std::string title = "nextpnr-ice40 - " + ctx->getChipName(); + setWindowTitle(title.c_str()); + + createMenu(); +} + +MainWindow::~MainWindow() {} + +void MainWindow::createMenu() +{ + QMenu *menu_Custom = new QMenu("&ICE 40", menuBar); + menuBar->addAction(menu_Custom->menuAction()); + +} diff --git a/gui/ice40/mainwindow.h b/gui/ice40/mainwindow.h new file mode 100644 index 00000000..e9c8ff77 --- /dev/null +++ b/gui/ice40/mainwindow.h @@ -0,0 +1,21 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +#include "../basewindow.h" + +// FIXME +USING_NEXTPNR_NAMESPACE + +class MainWindow : public BaseMainWindow +{ + Q_OBJECT + + public: + explicit MainWindow(Context *ctx, QWidget *parent = 0); + ~MainWindow(); + + public: + void createMenu(); +}; + +#endif // MAINWINDOW_H diff --git a/gui/mainwindow.cc b/gui/mainwindow.cc deleted file mode 100644 index 91232390..00000000 --- a/gui/mainwindow.cc +++ /dev/null @@ -1,145 +0,0 @@ -#include "mainwindow.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "designwidget.h" -#include "fpgaviewwidget.h" -#include "jsonparse.h" -#include "log.h" -#include "pythontab.h" -//#include "pack.h" -//#include "pcf.h" -#include "place_sa.h" -#include "pybindings.h" -#include "route.h" -//#include "bitstream.h" -#include "design_utils.h" - -MainWindow::MainWindow(Context *_ctx, QWidget *parent) - : QMainWindow(parent), ctx(_ctx) -{ - Q_INIT_RESOURCE(nextpnr); - - log_files.clear(); - log_streams.clear(); - log_write_function = [this](std::string text) { info->info(text); }; - - std::string title = "nextpnr-ice40 - " + ctx->getChipName(); - setWindowTitle(title.c_str()); - setObjectName(QStringLiteral("MainWindow")); - resize(1024, 768); - - createMenusAndBars(); - - QWidget *centralWidget = new QWidget(this); - - QGridLayout *gridLayout = new QGridLayout(centralWidget); - gridLayout->setSpacing(6); - gridLayout->setContentsMargins(11, 11, 11, 11); - - QSplitter *splitter_h = new QSplitter(Qt::Horizontal, centralWidget); - QSplitter *splitter_v = new QSplitter(Qt::Vertical, splitter_h); - splitter_h->addWidget(splitter_v); - - gridLayout->addWidget(splitter_h, 0, 0, 1, 1); - - setCentralWidget(centralWidget); - - DesignWidget *designview = new DesignWidget(ctx); - designview->setMinimumWidth(300); - designview->setMaximumWidth(300); - splitter_h->addWidget(designview); - - connect(designview, SIGNAL(info(std::string)), this, - SLOT(writeInfo(std::string))); - - tabWidget = new QTabWidget(); - tabWidget->addTab(new PythonTab(), "Python"); - info = new InfoTab(); - tabWidget->addTab(info, "Info"); - splitter_v->addWidget(new FPGAViewWidget()); - splitter_v->addWidget(tabWidget); -} - -MainWindow::~MainWindow() {} - -void MainWindow::writeInfo(std::string text) { info->info(text); } - -void MainWindow::createMenusAndBars() -{ - QAction *actionOpen = new QAction("Open", this); - QIcon icon1; - icon1.addFile(QStringLiteral(":/icons/resources/open.png")); - actionOpen->setIcon(icon1); - actionOpen->setShortcuts(QKeySequence::Open); - actionOpen->setStatusTip("Open an existing JSON file"); - connect(actionOpen, SIGNAL(triggered()), this, SLOT(open())); - - QAction *actionSave = new QAction("Save", this); - QIcon icon2; - icon2.addFile(QStringLiteral(":/icons/resources/save.png")); - actionSave->setIcon(icon2); - actionSave->setShortcuts(QKeySequence::Save); - actionSave->setStatusTip("Save the ASC to disk"); - connect(actionSave, SIGNAL(triggered()), this, SLOT(save())); - actionSave->setEnabled(false); - - QAction *actionExit = new QAction("Exit", this); - QIcon icon3; - icon3.addFile(QStringLiteral(":/icons/resources/exit.png")); - actionExit->setIcon(icon3); - actionExit->setShortcuts(QKeySequence::Quit); - actionExit->setStatusTip("Exit the application"); - connect(actionExit, SIGNAL(triggered()), this, SLOT(close())); - - QAction *actionAbout = new QAction("About", this); - - QMenuBar *menuBar = new QMenuBar(); - menuBar->setGeometry(QRect(0, 0, 1024, 27)); - QMenu *menu_File = new QMenu("&File", menuBar); - QMenu *menu_Help = new QMenu("&Help", menuBar); - menuBar->addAction(menu_File->menuAction()); - menuBar->addAction(menu_Help->menuAction()); - setMenuBar(menuBar); - - QToolBar *mainToolBar = new QToolBar(); - addToolBar(Qt::TopToolBarArea, mainToolBar); - - QStatusBar *statusBar = new QStatusBar(); - setStatusBar(statusBar); - - menu_File->addAction(actionOpen); - menu_File->addAction(actionSave); - menu_File->addSeparator(); - menu_File->addAction(actionExit); - menu_Help->addAction(actionAbout); - - mainToolBar->addAction(actionOpen); - mainToolBar->addAction(actionSave); -} - -void MainWindow::open() -{ - QString fileName = QFileDialog::getOpenFileName(this, QString(), QString(), - QString("*.json")); - if (!fileName.isEmpty()) { - tabWidget->setCurrentWidget(info); - - std::string fn = fileName.toStdString(); - std::istream *f = new std::ifstream(fn); - - parse_json_file(f, fn, ctx); - - // pack_design(ctx); - print_utilisation(ctx); - } -} - -bool MainWindow::save() { return false; } diff --git a/gui/mainwindow.h b/gui/mainwindow.h deleted file mode 100644 index 35d917d9..00000000 --- a/gui/mainwindow.h +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef MAINWINDOW_H -#define MAINWINDOW_H - -#include "infotab.h" -#include "nextpnr.h" - -#include -#include - -// FIXME -USING_NEXTPNR_NAMESPACE - -class MainWindow : public QMainWindow -{ - Q_OBJECT - - public: - explicit MainWindow(Context *ctx, QWidget *parent = 0); - ~MainWindow(); - Context *getContext() { return ctx; } - - private: - void createMenusAndBars(); - - private Q_SLOTS: - void writeInfo(std::string text); - void open(); - bool save(); - - private: - Context *ctx; - QTabWidget *tabWidget; - InfoTab *info; -}; - -#endif // MAINWINDOW_H -- cgit v1.2.3 From 0ed455096a9dd3b291c6b4a46b59c1ce6a506902 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Thu, 21 Jun 2018 13:52:58 +0200 Subject: make dummy target work as well --- dummy/main.cc | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 81 insertions(+), 4 deletions(-) diff --git a/dummy/main.cc b/dummy/main.cc index 6375eef9..7a961760 100644 --- a/dummy/main.cc +++ b/dummy/main.cc @@ -20,20 +20,97 @@ #ifdef MAIN_EXECUTABLE #include +#include +#include +#include "log.h" #include "mainwindow.h" #include "nextpnr.h" +#include "pybindings.h" +#include "version.h" USING_NEXTPNR_NAMESPACE int main(int argc, char *argv[]) { + namespace po = boost::program_options; + int rc = 0; + + log_files.push_back(stdout); + + po::options_description options("Allowed options"); + options.add_options()("help,h", "show help"); + options.add_options()("verbose,v", "verbose output"); + options.add_options()("force,f", "keep running after errors"); + options.add_options()("gui", "start gui"); + options.add_options()("version,V", "show version"); + po::positional_options_description pos; + pos.add("run", -1); + + po::variables_map vm; + try { + po::parsed_options parsed = po::command_line_parser(argc, argv) + .options(options) + .positional(pos) + .run(); + + po::store(parsed, vm); + + po::notify(vm); + } + + catch (std::exception &e) { + std::cout << e.what() << "\n"; + return 1; + } + + if (vm.count("help") || argc == 1) { + std::cout << boost::filesystem::basename(argv[0]) + << " -- Next Generation Place and Route (git " + "sha1 " GIT_COMMIT_HASH_STR ")\n"; + std::cout << "\n"; + std::cout << options << "\n"; + return argc != 1; + } + + if (vm.count("version")) { + std::cout << boost::filesystem::basename(argv[0]) + << " -- Next Generation Place and Route (git " + "sha1 " GIT_COMMIT_HASH_STR ")\n"; + return 1; + } + Context ctx(ArchArgs{}); + init_python(argv[0]); + python_export_global("ctx", ctx); + + if (vm.count("verbose")) { + ctx.verbose = true; + } + + if (vm.count("force")) { + ctx.force = true; + } + + if (vm.count("seed")) { + ctx.rngseed(vm["seed"].as()); + } + + if (vm.count("run")) { + std::vector files = + vm["run"].as>(); + for (auto filename : files) + execute_python_file(filename.c_str()); + } - QApplication a(argc, argv); - MainWindow w(&ctx); - w.show(); + if (vm.count("gui")) { + QApplication a(argc, argv); + MainWindow w(&ctx); + w.show(); - return a.exec(); + rc = a.exec(); + } + deinit_python(); + return rc; } #endif -- cgit v1.2.3 From 23fe31da44a2e2596335c09ae983217ffbc8f6b1 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Thu, 21 Jun 2018 13:55:36 +0200 Subject: cleanup --- dummy/main.cc | 2 ++ gui/basewindow.cc | 2 +- gui/basewindow.h | 7 +++---- gui/dummy/mainwindow.cc | 1 - gui/ice40/mainwindow.cc | 5 ++--- 5 files changed, 8 insertions(+), 9 deletions(-) diff --git a/dummy/main.cc b/dummy/main.cc index 7a961760..cef70235 100644 --- a/dummy/main.cc +++ b/dummy/main.cc @@ -42,6 +42,8 @@ int main(int argc, char *argv[]) options.add_options()("verbose,v", "verbose output"); options.add_options()("force,f", "keep running after errors"); options.add_options()("gui", "start gui"); + options.add_options()("run", po::value>(), + "python file to execute"); options.add_options()("version,V", "show version"); po::positional_options_description pos; pos.add("run", -1); diff --git a/gui/basewindow.cc b/gui/basewindow.cc index cbf0faae..fa9528fc 100644 --- a/gui/basewindow.cc +++ b/gui/basewindow.cc @@ -1,4 +1,3 @@ -#include "mainwindow.h" #include #include #include @@ -9,6 +8,7 @@ #include "fpgaviewwidget.h" #include "jsonparse.h" #include "log.h" +#include "mainwindow.h" #include "pythontab.h" //#include "pack.h" //#include "pcf.h" diff --git a/gui/basewindow.h b/gui/basewindow.h index 52efd6b1..630e0f84 100644 --- a/gui/basewindow.h +++ b/gui/basewindow.h @@ -5,12 +5,11 @@ #include "nextpnr.h" #include -#include #include #include -#include #include - +#include +#include // FIXME USING_NEXTPNR_NAMESPACE @@ -36,7 +35,7 @@ class BaseMainWindow : public QMainWindow Context *ctx; QTabWidget *tabWidget; InfoTab *info; - + QMenuBar *menuBar; QToolBar *mainToolBar; QStatusBar *statusBar; diff --git a/gui/dummy/mainwindow.cc b/gui/dummy/mainwindow.cc index dad73d7e..a9420524 100644 --- a/gui/dummy/mainwindow.cc +++ b/gui/dummy/mainwindow.cc @@ -15,5 +15,4 @@ void MainWindow::createMenu() { QMenu *menu_Custom = new QMenu("&Dummy", menuBar); menuBar->addAction(menu_Custom->menuAction()); - } diff --git a/gui/ice40/mainwindow.cc b/gui/ice40/mainwindow.cc index 4f53c551..3744cdc7 100644 --- a/gui/ice40/mainwindow.cc +++ b/gui/ice40/mainwindow.cc @@ -1,14 +1,14 @@ #include "mainwindow.h" #include #include +#include "bitstream.h" +#include "design_utils.h" #include "jsonparse.h" #include "log.h" #include "pack.h" #include "pcf.h" #include "place_sa.h" #include "route.h" -#include "bitstream.h" -#include "design_utils.h" MainWindow::MainWindow(Context *_ctx, QWidget *parent) : BaseMainWindow(_ctx, parent) @@ -25,5 +25,4 @@ void MainWindow::createMenu() { QMenu *menu_Custom = new QMenu("&ICE 40", menuBar); menuBar->addAction(menu_Custom->menuAction()); - } -- cgit v1.2.3 From 693c34ad0646aac1bb766e783eb94d710f8ff72b Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 21 Jun 2018 14:08:45 +0200 Subject: Improvements in router Signed-off-by: Clifford Wolf --- common/nextpnr.h | 1 + common/route.cc | 212 ++++++++++++++++++++++++++++++++++++++----------------- dummy/arch.h | 1 + ice40/arch.h | 3 +- ice40/main.cc | 6 ++ 5 files changed, 158 insertions(+), 65 deletions(-) diff --git a/common/nextpnr.h b/common/nextpnr.h index 5ccbf057..db6901fe 100644 --- a/common/nextpnr.h +++ b/common/nextpnr.h @@ -289,6 +289,7 @@ NEXTPNR_NAMESPACE_BEGIN struct Context : Arch { bool verbose = false; + bool debug = false; bool force = false; Context(ArchArgs args) : Arch(args) {} diff --git a/common/route.cc b/common/route.cc index 6a410397..cf87ebaa 100644 --- a/common/route.cc +++ b/common/route.cc @@ -23,6 +23,38 @@ #include "log.h" #include "route.h" +namespace std { +template <> +struct hash> +{ + std::size_t + operator()(const pair &arg) const noexcept + { + std::size_t seed = hash()(arg.first); + seed ^= hash()(arg.second) + + 0x9e3779b9 + (seed << 6) + (seed >> 2); + return seed; + } +}; + +template <> +struct hash< + pair> +{ + std::size_t + operator()(const pair &arg) const noexcept + { + std::size_t seed = hash()(arg.first); + seed ^= hash()(arg.second) + + 0x9e3779b9 + (seed << 6) + (seed >> 2); + return seed; + } +}; +} // namespace std + namespace { USING_NEXTPNR_NAMESPACE @@ -46,6 +78,12 @@ struct QueuedWire }; }; +struct RipupScoreboard +{ + std::unordered_map, int> wireScores; + std::unordered_map, int> pipScores; +}; + void ripup_net(Context *ctx, IdString net_name) { auto net_info = ctx->nets.at(net_name); @@ -62,7 +100,9 @@ void ripup_net(Context *ctx, IdString net_name) struct Router { Context *ctx; + RipupScoreboard scores; IdString net_name; + bool ripup; delay_t ripup_penalty; @@ -99,31 +139,41 @@ struct Router queue.pop(); for (auto pip : ctx->getPipsDownhill(qw.wire)) { - delay_t next_delay = qw.delay; - IdString ripupNet = net_name; + delay_t next_delay = + qw.delay + ctx->getPipDelay(pip).avgDelay(); + WireId next_wire = ctx->getPipDstWire(pip); + bool foundRipupNet = false; visitCnt++; - if (!ctx->checkPipAvail(pip)) { + if (!ctx->checkWireAvail(next_wire)) { if (!ripup) continue; - ripupNet = ctx->getPipNet(pip, true); - if (ripupNet == net_name) + IdString ripupWireNet = ctx->getWireNet(next_wire, true); + if (ripupWireNet == net_name || ripupWireNet == IdString()) continue; + auto it = scores.wireScores.find( + std::make_pair(ripupWireNet, next_wire)); + if (it != scores.wireScores.end()) + next_delay += it->second * ripup_penalty; + foundRipupNet = true; } - WireId next_wire = ctx->getPipDstWire(pip); - next_delay += ctx->getPipDelay(pip).avgDelay(); - - if (!ctx->checkWireAvail(next_wire)) { + if (!ctx->checkPipAvail(pip)) { if (!ripup) continue; - ripupNet = ctx->getWireNet(next_wire, true); - if (ripupNet == net_name) + IdString ripupPipNet = ctx->getPipNet(pip, true); + if (ripupPipNet == net_name || ripupPipNet == IdString()) continue; + auto it = scores.pipScores.find( + std::make_pair(ripupPipNet, pip)); + if (it != scores.pipScores.end()) + next_delay += it->second * ripup_penalty; + foundRipupNet = true; } - if (ripupNet != net_name) + if (foundRipupNet) next_delay += ripup_penalty; + assert(next_delay >= 0); if (visited.count(next_wire)) { @@ -131,7 +181,7 @@ struct Router next_delay + ctx->getDelayEpsilon()) continue; #if 0 // FIXME - if (ctx->verbose) + if (ctx->debug) log("Found better route to %s. Old vs new delay " "estimate: %.3f %.3f\n", ctx->getWireName(next_wire).c_str(), @@ -154,16 +204,17 @@ struct Router } } - Router(Context *ctx, WireId src_wire, WireId dst_wire, bool ripup = false, - delay_t ripup_penalty = 0) - : ctx(ctx), ripup(ripup), ripup_penalty(ripup_penalty) + Router(Context *ctx, RipupScoreboard &scores, WireId src_wire, + WireId dst_wire, bool ripup = false, delay_t ripup_penalty = 0) + : ctx(ctx), scores(scores), ripup(ripup), + ripup_penalty(ripup_penalty) { std::unordered_map src_wires; src_wires[src_wire] = 0; route(src_wires, dst_wire); routedOkay = visited.count(dst_wire); - if (ctx->verbose) { + if (ctx->debug) { log("Route (from destination to source):\n"); WireId cursor = dst_wire; @@ -180,17 +231,17 @@ struct Router } } - Router(Context *ctx, IdString net_name, bool ripup = false, - delay_t ripup_penalty = 0) - : ctx(ctx), net_name(net_name), ripup(ripup), + Router(Context *ctx, RipupScoreboard &scores, IdString net_name, + bool ripup = false, delay_t ripup_penalty = 0) + : ctx(ctx), scores(scores), net_name(net_name), ripup(ripup), ripup_penalty(ripup_penalty) { auto net_info = ctx->nets.at(net_name); - if (ctx->verbose) + if (ctx->debug) log("Routing net %s.\n", net_name.c_str(ctx)); - if (ctx->verbose) + if (ctx->debug) log(" Source: %s.%s.\n", net_info->driver.cell->name.c_str(ctx), net_info->driver.port.c_str(ctx)); @@ -201,7 +252,7 @@ struct Router net_info->driver.cell->name.c_str(ctx), net_info->driver.cell->type.c_str(ctx)); - if (ctx->verbose) + if (ctx->debug) log(" Source bel: %s\n", ctx->getBelName(src_bel).c_str(ctx)); IdString driver_port = net_info->driver.port; @@ -220,7 +271,7 @@ struct Router net_info->driver.cell->name.c_str(ctx), ctx->getBelName(src_bel).c_str(ctx)); - if (ctx->verbose) + if (ctx->debug) log(" Source wire: %s\n", ctx->getWireName(src_wire).c_str(ctx)); std::unordered_map src_wires; @@ -232,7 +283,7 @@ struct Router ctx->shuffle(users_array); for (auto &user_it : users_array) { - if (ctx->verbose) + if (ctx->debug) log(" Route to: %s.%s.\n", user_it.cell->name.c_str(ctx), user_it.port.c_str(ctx)); @@ -243,7 +294,7 @@ struct Router user_it.cell->name.c_str(ctx), user_it.cell->type.c_str(ctx)); - if (ctx->verbose) + if (ctx->debug) log(" Destination bel: %s\n", ctx->getBelName(dst_bel).c_str(ctx)); @@ -264,7 +315,7 @@ struct Router user_it.cell->name.c_str(ctx), ctx->getBelName(dst_bel).c_str(ctx)); - if (ctx->verbose) { + if (ctx->debug) { log(" Destination wire: %s\n", ctx->getWireName(dst_wire).c_str(ctx)); log(" Path delay estimate: %.2f\n", @@ -274,7 +325,7 @@ struct Router route(src_wires, dst_wire); if (visited.count(dst_wire) == 0) { - if (ctx->verbose) + if (ctx->debug) log("Failed to route %s -> %s.\n", ctx->getWireName(src_wire).c_str(ctx), ctx->getWireName(dst_wire).c_str(ctx)); @@ -287,18 +338,18 @@ struct Router return; } - if (ctx->verbose) + if (ctx->debug) log(" Final path delay: %.3f\n", ctx->getDelayNS(visited[dst_wire].delay)); maxDelay = fmaxf(maxDelay, visited[dst_wire].delay); - if (ctx->verbose) + if (ctx->debug) log(" Route (from destination to source):\n"); WireId cursor = dst_wire; while (1) { - if (ctx->verbose) + if (ctx->debug) log(" %8.3f %s\n", ctx->getDelayNS(visited[cursor].delay), ctx->getWireName(cursor).c_str(ctx)); @@ -306,22 +357,31 @@ struct Router if (src_wires.count(cursor)) break; - IdString conflicting_net = ctx->getWireNet(cursor, true); + IdString conflicting_wire_net = ctx->getWireNet(cursor, true); + IdString conflicting_pip_net = + ctx->getPipNet(visited[cursor].pip, true); - if (conflicting_net != IdString()) { + if (conflicting_wire_net != IdString()) { assert(ripup); - assert(conflicting_net != net_name); - ripup_net(ctx, conflicting_net); - rippedNets.insert(conflicting_net); + assert(conflicting_wire_net != net_name); + ripup_net(ctx, conflicting_wire_net); + rippedNets.insert(conflicting_wire_net); + scores.wireScores[std::make_pair(net_name, cursor)]++; + scores.wireScores[std::make_pair(conflicting_wire_net, + cursor)]++; } - conflicting_net = ctx->getPipNet(visited[cursor].pip, true); - - if (conflicting_net != IdString()) { + if (conflicting_pip_net != IdString()) { assert(ripup); - assert(conflicting_net != net_name); - ripup_net(ctx, conflicting_net); - rippedNets.insert(conflicting_net); + assert(conflicting_pip_net != net_name); + if (conflicting_wire_net != conflicting_pip_net) { + ripup_net(ctx, conflicting_pip_net); + rippedNets.insert(conflicting_pip_net); + } + scores.pipScores[std::make_pair(net_name, + visited[cursor].pip)]++; + scores.pipScores[std::make_pair(conflicting_pip_net, + visited[cursor].pip)]++; } net_info->wires[cursor] = visited[cursor].pip; @@ -343,7 +403,8 @@ NEXTPNR_NAMESPACE_BEGIN bool route_design(Context *ctx) { - delay_t ripup_penalty = 5; + delay_t ripup_penalty = ctx->getRipupDelayPenalty(); + RipupScoreboard scores; log_info("Routing..\n"); @@ -425,17 +486,23 @@ bool route_design(Context *ctx) while (!netsQueue.empty()) { if (iterCnt == 200) { - log_info("giving up after %d iterations.\n", iterCnt); + log_warning("giving up after %d iterations.\n", iterCnt); return false; } - log_info("-- %d --\n", ++iterCnt); + + iterCnt++; + if (ctx->verbose) + log_info("-- %d --\n", iterCnt); int visitCnt = 0, revisitCnt = 0, netCnt = 0; std::unordered_set ripupQueue; - log_info("routing queue contains %d nets.\n", int(netsQueue.size())); - bool printNets = netsQueue.size() < 10; + if (ctx->verbose || iterCnt == 1) + log_info("routing queue contains %d nets.\n", + int(netsQueue.size())); + + bool printNets = ctx->verbose && (netsQueue.size() < 10); std::vector netsArray(netsQueue.begin(), netsQueue.end()); ctx->sorted_shuffle(netsArray); @@ -446,7 +513,7 @@ bool route_design(Context *ctx) log_info(" routing net %s. (%d users)\n", net_name.c_str(ctx), int(ctx->nets.at(net_name)->users.size())); - Router router(ctx, net_name, false); + Router router(ctx, scores, net_name, false); netCnt++; visitCnt += router.visitCnt; @@ -459,23 +526,29 @@ bool route_design(Context *ctx) ripupQueue.insert(net_name); } - if (!printNets && netCnt % 100 == 0) + if ((ctx->verbose || iterCnt == 1) && !printNets && + (netCnt % 100 == 0)) log_info(" processed %d nets. (%d routed, %d failed)\n", netCnt, netCnt - int(ripupQueue.size()), int(ripupQueue.size())); } - if (netCnt % 100 != 0) + int normalRouteCnt = netCnt - int(ripupQueue.size()); + + if ((ctx->verbose || iterCnt == 1) && (netCnt % 100 != 0)) log_info(" processed %d nets. (%d routed, %d failed)\n", netCnt, - netCnt - int(ripupQueue.size()), int(ripupQueue.size())); - log_info(" routing pass visited %d PIPs (%.2f%% revisits).\n", - visitCnt, (100.0 * revisitCnt) / visitCnt); + normalRouteCnt, int(ripupQueue.size())); + + if (ctx->verbose) + log_info(" routing pass visited %d PIPs (%.2f%% revisits).\n", + visitCnt, (100.0 * revisitCnt) / visitCnt); if (!ripupQueue.empty()) { - log_info("failed to route %d nets. re-routing in ripup mode.\n", - int(ripupQueue.size())); + if (ctx->verbose || iterCnt == 1) + log_info("failed to route %d nets. re-routing in ripup mode.\n", + int(ripupQueue.size())); - printNets = ripupQueue.size() < 10; + printNets = ctx->verbose && (ripupQueue.size() < 10); visitCnt = 0; revisitCnt = 0; @@ -492,8 +565,7 @@ bool route_design(Context *ctx) net_name.c_str(ctx), int(ctx->nets.at(net_name)->users.size())); - Router router(ctx, net_name, true, - ripup_penalty * (iterCnt - 1)); + Router router(ctx, scores, net_name, true, ripup_penalty); netCnt++; visitCnt += router.visitCnt; @@ -521,22 +593,33 @@ bool route_design(Context *ctx) ripCnt += router.rippedNets.size(); - if (!printNets && netCnt % 100 == 0) + if ((ctx->verbose || iterCnt == 1) && !printNets && + (netCnt % 100 == 0)) log_info(" routed %d nets, ripped %d nets.\n", netCnt, ripCnt); } - if (netCnt % 100 != 0) + if ((ctx->verbose || iterCnt == 1) && (netCnt % 100 != 0)) log_info(" routed %d nets, ripped %d nets.\n", netCnt, ripCnt); - log_info(" routing pass visited %d PIPs (%.2f%% revisits).\n", - visitCnt, (100.0 * revisitCnt) / visitCnt); + if (ctx->verbose) + log_info(" routing pass visited %d PIPs (%.2f%% revisits).\n", + visitCnt, (100.0 * revisitCnt) / visitCnt); - if (!netsQueue.empty()) + if (ctx->verbose && !netsQueue.empty()) log_info(" ripped up %d previously routed nets. continue " "routing.\n", int(netsQueue.size())); } + + if (!ctx->verbose) + log_info("iteration %d: routed %d nets without ripup, routed %d " + "nets with ripup.\n", + iterCnt, normalRouteCnt, int(ripupQueue.size())); + + if (iterCnt == 8 || iterCnt == 16 || iterCnt == 32 || iterCnt == 64 || + iterCnt == 128) + ripup_penalty += ctx->getRipupDelayPenalty(); } log_info("routing complete after %d iterations.\n", iterCnt); @@ -546,7 +629,8 @@ bool route_design(Context *ctx) bool get_actual_route_delay(Context *ctx, WireId src_wire, WireId dst_wire, delay_t &delay) { - Router router(ctx, src_wire, dst_wire); + RipupScoreboard scores; + Router router(ctx, scores, src_wire, dst_wire); if (router.routedOkay) delay = router.visited.at(dst_wire).delay; return router.routedOkay; diff --git a/dummy/arch.h b/dummy/arch.h index 43ab3290..929c172a 100644 --- a/dummy/arch.h +++ b/dummy/arch.h @@ -123,6 +123,7 @@ struct Arch : BaseCtx void estimatePosition(BelId bel, int &x, int &y, bool &gb) const; delay_t estimateDelay(WireId src, WireId dst) const; delay_t getDelayEpsilon() const { return 0.01; } + delay_t getRipupDelayPenalty() const { return 1.0; } float getDelayNS(delay_t v) const { return v; } std::vector getFrameGraphics() const; diff --git a/ice40/arch.h b/ice40/arch.h index 85fb9fc0..4896736b 100644 --- a/ice40/arch.h +++ b/ice40/arch.h @@ -755,7 +755,8 @@ struct Arch : BaseCtx void estimatePosition(BelId bel, int &x, int &y, bool &gb) const; delay_t estimateDelay(WireId src, WireId dst) const; - delay_t getDelayEpsilon() const { return 10; } + delay_t getDelayEpsilon() const { return 20; } + delay_t getRipupDelayPenalty() const { return 200; } float getDelayNS(delay_t v) const { return v * 0.001; } // ------------------------------------------------- diff --git a/ice40/main.cc b/ice40/main.cc index fcf112e6..e86cd5b1 100644 --- a/ice40/main.cc +++ b/ice40/main.cc @@ -69,6 +69,7 @@ int main(int argc, char *argv[]) po::options_description options("Allowed options"); options.add_options()("help,h", "show help"); options.add_options()("verbose,v", "verbose output"); + options.add_options()("debug", "debug output"); options.add_options()("force,f", "keep running after errors"); options.add_options()("gui", "start gui"); options.add_options()("svg", "dump SVG file"); @@ -201,6 +202,11 @@ int main(int argc, char *argv[]) ctx.verbose = true; } + if (vm.count("debug")) { + ctx.verbose = true; + ctx.debug = true; + } + if (vm.count("force")) { ctx.force = true; } -- cgit v1.2.3 From 993f6ef7d31ceee5fc71a99fcec19b521694e4f3 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 21 Jun 2018 14:09:50 +0200 Subject: Improve log messages, move many messages to verbose mode Signed-off-by: Clifford Wolf --- common/design_utils.cc | 8 +++++--- common/log.cc | 12 +----------- common/log.h | 18 +----------------- common/place_sa.cc | 8 +++++--- common/route.cc | 1 + frontend/json/jsonparse.cc | 9 ++++++--- ice40/pack.cc | 28 +++++++++++++++++----------- 7 files changed, 36 insertions(+), 48 deletions(-) diff --git a/common/design_utils.cc b/common/design_utils.cc index 4fbd16f1..535b6fda 100644 --- a/common/design_utils.cc +++ b/common/design_utils.cc @@ -64,11 +64,13 @@ void print_utilisation(const Context *ctx) for (auto bel : ctx->getBels()) { available_types[ctx->getBelType(bel)]++; } - log("\nDesign utilisation:\n"); + log_break(); + log_info("Device utilisation:\n"); for (auto type : available_types) { - log("\t%20s: %5d/%5d\n", ctx->belTypeToId(type.first).c_str(ctx), - get_or_default(used_types, type.first, 0), type.second); + log_info("\t%20s: %5d/%5d\n", ctx->belTypeToId(type.first).c_str(ctx), + get_or_default(used_types, type.first, 0), type.second); } + log_break(); } NEXTPNR_NAMESPACE_END diff --git a/common/log.cc b/common/log.cc index 2868e03f..b0cd802a 100644 --- a/common/log.cc +++ b/common/log.cc @@ -212,7 +212,7 @@ void log_cmd_error(const char *format, ...) logv_error(format, ap); } -void log_spacer() +void log_break() { if (log_newline_count < 2) log("\n"); @@ -220,12 +220,6 @@ void log_spacer() log("\n"); } -void log_push() {} - -void log_pop() { log_flush(); } - -void log_reset_stack() { log_flush(); } - void log_flush() { for (auto f : log_files) @@ -235,8 +229,4 @@ void log_flush() f->flush(); } -void log_cell(CellInfo *cell, std::string indent) {} - -void log_net(NetInfo *net, std::string indent) {} - NEXTPNR_NAMESPACE_END diff --git a/common/log.h b/common/log.h index 597b5fac..381843b3 100644 --- a/common/log.h +++ b/common/log.h @@ -71,25 +71,9 @@ NXP_NORETURN void log_error(const char *format, ...) NXP_NORETURN void log_cmd_error(const char *format, ...) NXP_ATTRIBUTE(format(printf, 1, 2), noreturn); -void log_spacer(); -void log_push(); -void log_pop(); - -void log_backtrace(const char *prefix, int levels); -void log_reset_stack(); +void log_break(); void log_flush(); -/* -const char *log_id(RTLIL::IdString id); - -template static inline const char *log_id(T *obj) { - return log_id(obj->name); -} -*/ - -void log_cell(CellInfo *cell, std::string indent = ""); -void log_net(NetInfo *net, std::string indent = ""); - #ifndef NDEBUG static inline void log_assert_worker(bool cond, const char *expr, const char *file, int line) diff --git a/common/place_sa.cc b/common/place_sa.cc index 2f8fb122..591766aa 100644 --- a/common/place_sa.cc +++ b/common/place_sa.cc @@ -77,6 +77,8 @@ class SAPlacer bool place() { + log_break(); + size_t placed_cells = 0; // Initial constraints placer for (auto cell_entry : ctx->cells) { @@ -408,9 +410,9 @@ class SAPlacer delta = new_wirelength - curr_wirelength; n_move++; // SA acceptance criterea - if (delta < 0 || - (temp > 1e-6 && (ctx->rng() / float(0x3fffffff)) <= - std::exp(-(delta / 2) / temp))) { + if (delta < 0 || (temp > 1e-6 && + (ctx->rng() / float(0x3fffffff)) <= + std::exp(-(delta / 2) / temp))) { n_accept++; if (delta < 2) improved = true; diff --git a/common/route.cc b/common/route.cc index cf87ebaa..bdb2f5b5 100644 --- a/common/route.cc +++ b/common/route.cc @@ -406,6 +406,7 @@ bool route_design(Context *ctx) delay_t ripup_penalty = ctx->getRipupDelayPenalty(); RipupScoreboard scores; + log_break(); log_info("Routing..\n"); std::unordered_set netsQueue; diff --git a/frontend/json/jsonparse.cc b/frontend/json/jsonparse.cc index a936bdaa..32ae0953 100644 --- a/frontend/json/jsonparse.cc +++ b/frontend/json/jsonparse.cc @@ -659,7 +659,8 @@ static void insert_iobuf(Context *ctx, NetInfo *net, PortType type, std::copy(net->attrs.begin(), net->attrs.end(), std::inserter(iobuf->attrs, iobuf->attrs.begin())); if (type == PORT_IN) { - log_info("processing input port %s\n", name.c_str()); + if (ctx->verbose) + log_info("processing input port %s\n", name.c_str()); iobuf->type = ctx->id("$nextpnr_ibuf"); iobuf->ports[ctx->id("O")] = PortInfo{ctx->id("O"), net, PORT_OUT}; // Special case: input, etc, directly drives inout @@ -671,7 +672,8 @@ static void insert_iobuf(Context *ctx, NetInfo *net, PortType type, net->driver.port = ctx->id("O"); net->driver.cell = iobuf; } else if (type == PORT_OUT) { - log_info("processing output port %s\n", name.c_str()); + if (ctx->verbose) + log_info("processing output port %s\n", name.c_str()); iobuf->type = ctx->id("$nextpnr_obuf"); iobuf->ports[ctx->id("I")] = PortInfo{ctx->id("I"), net, PORT_IN}; PortRef ref; @@ -679,7 +681,8 @@ static void insert_iobuf(Context *ctx, NetInfo *net, PortType type, ref.port = ctx->id("I"); net->users.push_back(ref); } else if (type == PORT_INOUT) { - log_info("processing inout port %s\n", name.c_str()); + if (ctx->verbose) + log_info("processing inout port %s\n", name.c_str()); iobuf->type = ctx->id("$nextpnr_iobuf"); iobuf->ports[ctx->id("I")] = PortInfo{ctx->id("I"), nullptr, PORT_IN}; diff --git a/ice40/pack.cc b/ice40/pack.cc index 853f510e..8a6f1c45 100644 --- a/ice40/pack.cc +++ b/ice40/pack.cc @@ -36,8 +36,9 @@ static void pack_lut_lutffs(Context *ctx) std::vector new_cells; for (auto cell : ctx->cells) { CellInfo *ci = cell.second; - log_info("cell '%s' is of type '%s'\n", ci->name.c_str(ctx), - ci->type.c_str(ctx)); + if (ctx->verbose) + log_info("cell '%s' is of type '%s'\n", ci->name.c_str(ctx), + ci->type.c_str(ctx)); if (is_lut(ctx, ci)) { CellInfo *packed = create_ice_cell(ctx, "ICESTORM_LC", ci->name.str(ctx) + "_LC"); @@ -45,8 +46,9 @@ static void pack_lut_lutffs(Context *ctx) std::inserter(packed->attrs, packed->attrs.begin())); packed_cells.insert(ci->name); new_cells.push_back(packed); - log_info("packed cell %s into %s\n", ci->name.c_str(ctx), - packed->name.c_str(ctx)); + if (ctx->verbose) + log_info("packed cell %s into %s\n", ci->name.c_str(ctx), + packed->name.c_str(ctx)); // See if we can pack into a DFF // TODO: LUT cascade NetInfo *o = ci->ports.at(ctx->id("O")).net; @@ -54,7 +56,8 @@ static void pack_lut_lutffs(Context *ctx) auto lut_bel = ci->attrs.find(ctx->id("BEL")); bool packed_dff = false; if (dff) { - log_info("found attached dff %s\n", dff->name.c_str(ctx)); + if (ctx->verbose) + log_info("found attached dff %s\n", dff->name.c_str(ctx)); auto dff_bel = dff->attrs.find(ctx->id("BEL")); if (lut_bel != ci->attrs.end() && dff_bel != dff->attrs.end() && lut_bel->second != dff_bel->second) { @@ -66,8 +69,9 @@ static void pack_lut_lutffs(Context *ctx) if (dff_bel != dff->attrs.end()) packed->attrs[ctx->id("BEL")] = dff_bel->second; packed_cells.insert(dff->name); - log_info("packed cell %s into %s\n", dff->name.c_str(ctx), - packed->name.c_str(ctx)); + if (ctx->verbose) + log_info("packed cell %s into %s\n", + dff->name.c_str(ctx), packed->name.c_str(ctx)); packed_dff = true; } } @@ -99,8 +103,9 @@ static void pack_nonlut_ffs(Context *ctx) ci->name.str(ctx) + "_DFFLC"); std::copy(ci->attrs.begin(), ci->attrs.end(), std::inserter(packed->attrs, packed->attrs.begin())); - log_info("packed cell %s into %s\n", ci->name.c_str(ctx), - packed->name.c_str(ctx)); + if (ctx->verbose) + log_info("packed cell %s into %s\n", ci->name.c_str(ctx), + packed->name.c_str(ctx)); packed_cells.insert(ci->name); new_cells.push_back(packed); dff_to_lc(ctx, ci, packed, true); @@ -242,8 +247,9 @@ static void set_net_constant(const Context *ctx, NetInfo *orig, for (auto user : orig->users) { if (user.cell != nullptr) { CellInfo *uc = user.cell; - log_info("%s user %s\n", orig->name.c_str(ctx), - uc->name.c_str(ctx)); + if (ctx->verbose) + log_info("%s user %s\n", orig->name.c_str(ctx), + uc->name.c_str(ctx)); if ((is_lut(ctx, uc) || is_lc(ctx, uc)) && (user.port.str(ctx).at(0) == 'I') && !constval) { uc->ports[user.port].net = nullptr; -- cgit v1.2.3 From 08020400b379a0c2d7069bbd62f43782d438598b Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 21 Jun 2018 14:16:07 +0200 Subject: Fix build of "dummy" architexture Signed-off-by: Clifford Wolf --- common/route.cc | 44 ++++++++++++++++++-------------------------- 1 file changed, 18 insertions(+), 26 deletions(-) diff --git a/common/route.cc b/common/route.cc index bdb2f5b5..bf11b7d2 100644 --- a/common/route.cc +++ b/common/route.cc @@ -23,41 +23,32 @@ #include "log.h" #include "route.h" -namespace std { -template <> -struct hash> +namespace { + +USING_NEXTPNR_NAMESPACE + +struct hash_id_wire { - std::size_t - operator()(const pair &arg) const noexcept + std::size_t operator()(const std::pair &arg) const + noexcept { - std::size_t seed = hash()(arg.first); - seed ^= hash()(arg.second) + - 0x9e3779b9 + (seed << 6) + (seed >> 2); + std::size_t seed = std::hash()(arg.first); + seed ^= std::hash()(arg.second) + 0x9e3779b9 + (seed << 6) + + (seed >> 2); return seed; } }; -template <> -struct hash< - pair> +struct hash_id_pip { - std::size_t - operator()(const pair &arg) const noexcept + std::size_t operator()(const std::pair &arg) const noexcept { - std::size_t seed = hash()(arg.first); - seed ^= hash()(arg.second) + - 0x9e3779b9 + (seed << 6) + (seed >> 2); + std::size_t seed = std::hash()(arg.first); + seed ^= std::hash()(arg.second) + 0x9e3779b9 + (seed << 6) + + (seed >> 2); return seed; } }; -} // namespace std - -namespace { - -USING_NEXTPNR_NAMESPACE struct QueuedWire { @@ -80,8 +71,9 @@ struct QueuedWire struct RipupScoreboard { - std::unordered_map, int> wireScores; - std::unordered_map, int> pipScores; + std::unordered_map, int, hash_id_wire> + wireScores; + std::unordered_map, int, hash_id_pip> pipScores; }; void ripup_net(Context *ctx, IdString net_name) -- cgit v1.2.3 From 2d405f966b4e69b95cd4ea9acbb5438e1fa91e69 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Thu, 21 Jun 2018 14:12:02 +0200 Subject: Add graphics view in tab --- gui/basewindow.cc | 6 +++++- gui/basewindow.h | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/gui/basewindow.cc b/gui/basewindow.cc index fa9528fc..25603322 100644 --- a/gui/basewindow.cc +++ b/gui/basewindow.cc @@ -57,7 +57,11 @@ BaseMainWindow::BaseMainWindow(Context *_ctx, QWidget *parent) tabWidget->addTab(new PythonTab(), "Python"); info = new InfoTab(); tabWidget->addTab(info, "Info"); - splitter_v->addWidget(new FPGAViewWidget()); + + centralTabWidget = new QTabWidget(); + centralTabWidget->addTab(new FPGAViewWidget(), "Graphics"); + + splitter_v->addWidget(centralTabWidget); splitter_v->addWidget(tabWidget); } diff --git a/gui/basewindow.h b/gui/basewindow.h index 630e0f84..1d0ac468 100644 --- a/gui/basewindow.h +++ b/gui/basewindow.h @@ -34,6 +34,7 @@ class BaseMainWindow : public QMainWindow protected: Context *ctx; QTabWidget *tabWidget; + QTabWidget *centralTabWidget; InfoTab *info; QMenuBar *menuBar; -- cgit v1.2.3 From 097df1869d654b1214b925fe991aa09d2ef5b3cd Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Thu, 21 Jun 2018 15:41:40 +0200 Subject: Added task manager and worker thread for ice40 --- gui/basewindow.cc | 29 ++----------------------- gui/basewindow.h | 9 +++++--- gui/dummy/mainwindow.cc | 9 ++++++++ gui/dummy/mainwindow.h | 6 ++++- gui/ice40/mainwindow.cc | 21 ++++++++++++++++++ gui/ice40/mainwindow.h | 10 ++++++++- gui/ice40/worker.cc | 58 +++++++++++++++++++++++++++++++++++++++++++++++++ gui/ice40/worker.h | 37 +++++++++++++++++++++++++++++++ 8 files changed, 147 insertions(+), 32 deletions(-) create mode 100644 gui/ice40/worker.cc create mode 100644 gui/ice40/worker.h diff --git a/gui/basewindow.cc b/gui/basewindow.cc index 25603322..1e6b171f 100644 --- a/gui/basewindow.cc +++ b/gui/basewindow.cc @@ -3,28 +3,22 @@ #include #include #include -#include #include "designwidget.h" #include "fpgaviewwidget.h" #include "jsonparse.h" #include "log.h" #include "mainwindow.h" #include "pythontab.h" -//#include "pack.h" -//#include "pcf.h" -#include "place_sa.h" -#include "route.h" -//#include "bitstream.h" -#include "design_utils.h" + BaseMainWindow::BaseMainWindow(Context *_ctx, QWidget *parent) : QMainWindow(parent), ctx(_ctx) { Q_INIT_RESOURCE(nextpnr); + qRegisterMetaType(); log_files.clear(); log_streams.clear(); - log_write_function = [this](std::string text) { info->info(text); }; setObjectName(QStringLiteral("BaseMainWindow")); resize(1024, 768); @@ -121,22 +115,3 @@ void BaseMainWindow::createMenusAndBars() mainToolBar->addAction(actionOpen); mainToolBar->addAction(actionSave); } - -void BaseMainWindow::open() -{ - QString fileName = QFileDialog::getOpenFileName(this, QString(), QString(), - QString("*.json")); - if (!fileName.isEmpty()) { - tabWidget->setCurrentWidget(info); - - std::string fn = fileName.toStdString(); - std::istream *f = new std::ifstream(fn); - - parse_json_file(f, fn, ctx); - - // pack_design(ctx); - print_utilisation(ctx); - } -} - -bool BaseMainWindow::save() { return false; } diff --git a/gui/basewindow.h b/gui/basewindow.h index 1d0ac468..d6915ae9 100644 --- a/gui/basewindow.h +++ b/gui/basewindow.h @@ -14,13 +14,15 @@ // FIXME USING_NEXTPNR_NAMESPACE +Q_DECLARE_METATYPE(std::string) + class BaseMainWindow : public QMainWindow { Q_OBJECT public: explicit BaseMainWindow(Context *ctx, QWidget *parent = 0); - ~BaseMainWindow(); + virtual ~BaseMainWindow(); Context *getContext() { return ctx; } protected: @@ -28,8 +30,9 @@ class BaseMainWindow : public QMainWindow protected Q_SLOTS: void writeInfo(std::string text); - void open(); - bool save(); + + virtual void open() = 0; + virtual bool save() = 0; protected: Context *ctx; diff --git a/gui/dummy/mainwindow.cc b/gui/dummy/mainwindow.cc index a9420524..f714e30e 100644 --- a/gui/dummy/mainwindow.cc +++ b/gui/dummy/mainwindow.cc @@ -16,3 +16,12 @@ void MainWindow::createMenu() QMenu *menu_Custom = new QMenu("&Dummy", menuBar); menuBar->addAction(menu_Custom->menuAction()); } + +void MainWindow::open() +{ +} + +bool MainWindow::save() +{ + return false; +} \ No newline at end of file diff --git a/gui/dummy/mainwindow.h b/gui/dummy/mainwindow.h index e9c8ff77..ea4480fb 100644 --- a/gui/dummy/mainwindow.h +++ b/gui/dummy/mainwindow.h @@ -12,10 +12,14 @@ class MainWindow : public BaseMainWindow public: explicit MainWindow(Context *ctx, QWidget *parent = 0); - ~MainWindow(); + virtual ~MainWindow(); public: void createMenu(); + + protected Q_SLOTS: + virtual void open(); + virtual bool save(); }; #endif // MAINWINDOW_H diff --git a/gui/ice40/mainwindow.cc b/gui/ice40/mainwindow.cc index 3744cdc7..dafd92e9 100644 --- a/gui/ice40/mainwindow.cc +++ b/gui/ice40/mainwindow.cc @@ -1,5 +1,6 @@ #include "mainwindow.h" #include +#include #include #include "bitstream.h" #include "design_utils.h" @@ -17,6 +18,10 @@ MainWindow::MainWindow(Context *_ctx, QWidget *parent) setWindowTitle(title.c_str()); createMenu(); + + task = new TaskManager(_ctx); + connect(task, SIGNAL(log(std::string)), this, + SLOT(writeInfo(std::string))); } MainWindow::~MainWindow() {} @@ -26,3 +31,19 @@ void MainWindow::createMenu() QMenu *menu_Custom = new QMenu("&ICE 40", menuBar); menuBar->addAction(menu_Custom->menuAction()); } + +void MainWindow::open() +{ + QString fileName = QFileDialog::getOpenFileName(this, QString(), QString(), + QString("*.json")); + if (!fileName.isEmpty()) { + tabWidget->setCurrentWidget(info); + + std::string fn = fileName.toStdString(); + task->parsejson(fn); + } +} +bool MainWindow::save() +{ + return false; +} \ No newline at end of file diff --git a/gui/ice40/mainwindow.h b/gui/ice40/mainwindow.h index e9c8ff77..fd65f9ae 100644 --- a/gui/ice40/mainwindow.h +++ b/gui/ice40/mainwindow.h @@ -2,6 +2,7 @@ #define MAINWINDOW_H #include "../basewindow.h" +#include "worker.h" // FIXME USING_NEXTPNR_NAMESPACE @@ -12,10 +13,17 @@ class MainWindow : public BaseMainWindow public: explicit MainWindow(Context *ctx, QWidget *parent = 0); - ~MainWindow(); + virtual ~MainWindow(); public: void createMenu(); + + protected Q_SLOTS: + virtual void open(); + virtual bool save(); + + private: + TaskManager *task; }; #endif // MAINWINDOW_H diff --git a/gui/ice40/worker.cc b/gui/ice40/worker.cc new file mode 100644 index 00000000..5a8ff0e9 --- /dev/null +++ b/gui/ice40/worker.cc @@ -0,0 +1,58 @@ +#include "worker.h" +#include +#include "jsonparse.h" +#include "log.h" +#include "pack.h" +#include "pcf.h" +#include "place_sa.h" +#include "route.h" +#include "bitstream.h" +#include "design_utils.h" +#include "timing.h" + +Worker::Worker(Context *_ctx) : ctx(_ctx) +{ + log_write_function = [this](std::string text) { Q_EMIT log(text); }; +} + +void Worker::parsejson(const std::string &filename) +{ + std::string fn = filename; + std::istream *f = new std::ifstream(fn); + + parse_json_file(f, fn, ctx); + if (!pack_design(ctx)) + log_error("Packing design failed.\n"); + double freq = 50e6; + assign_budget(ctx, freq); + print_utilisation(ctx); + + if (!place_design_sa(ctx)) + log_error("Placing design failed.\n"); + if (!route_design(ctx)) + log_error("Routing design failed.\n"); + print_utilisation(ctx); + Q_EMIT log("done"); +} + + +TaskManager::TaskManager(Context *ctx) +{ + Worker *worker = new Worker(ctx); + worker->moveToThread(&workerThread); + connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater); + connect(this, &TaskManager::parsejson, worker, &Worker::parsejson); + connect(worker, &Worker::log, this, &TaskManager::info); + workerThread.start(); +} + +TaskManager::~TaskManager() +{ + workerThread.quit(); + workerThread.wait(); +} + +void TaskManager::info(const std::string &result) +{ + Q_EMIT log(result); +} \ No newline at end of file diff --git a/gui/ice40/worker.h b/gui/ice40/worker.h new file mode 100644 index 00000000..5dc25d89 --- /dev/null +++ b/gui/ice40/worker.h @@ -0,0 +1,37 @@ +#ifndef WORKER_H +#define WORKER_H + +#include "nextpnr.h" +#include + +// FIXME +USING_NEXTPNR_NAMESPACE + +class Worker : public QObject +{ + Q_OBJECT +public: + Worker(Context *ctx); +public Q_SLOTS: + void parsejson(const std::string &filename); +Q_SIGNALS: + void log(const std::string &text); +private: + Context *ctx; +}; + +class TaskManager : public QObject +{ + Q_OBJECT + QThread workerThread; +public: + TaskManager(Context *ctx); + ~TaskManager(); +public Q_SLOTS: + void info(const std::string &text); +Q_SIGNALS: + void parsejson(const std::string &); + void log(const std::string &text); +}; + +#endif // WORKER_H -- cgit v1.2.3 From a29bfc788eba9f11f1e0cd3d62a32c3894cddf49 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 21 Jun 2018 15:47:41 +0200 Subject: Add ctx->checksum(), slightly improve log messages Signed-off-by: Clifford Wolf --- common/design_utils.cc | 6 ++- common/nextpnr.cc | 123 +++++++++++++++++++++++++++++++++++++++++++++ common/nextpnr.h | 8 ++- common/place_sa.cc | 1 + common/route.cc | 2 + common/timing.cc | 3 ++ dummy/arch.cc | 6 +++ dummy/arch.h | 4 ++ frontend/json/jsonparse.cc | 3 ++ ice40/arch.h | 16 ++++++ ice40/pack.cc | 2 + 11 files changed, 171 insertions(+), 3 deletions(-) diff --git a/common/design_utils.cc b/common/design_utils.cc index 535b6fda..fa914ee2 100644 --- a/common/design_utils.cc +++ b/common/design_utils.cc @@ -67,8 +67,10 @@ void print_utilisation(const Context *ctx) log_break(); log_info("Device utilisation:\n"); for (auto type : available_types) { - log_info("\t%20s: %5d/%5d\n", ctx->belTypeToId(type.first).c_str(ctx), - get_or_default(used_types, type.first, 0), type.second); + IdString type_id = ctx->belTypeToId(type.first); + int used_bels = get_or_default(used_types, type.first, 0); + log_info("\t%20s: %5d/%5d %5d%%\n", type_id.c_str(ctx), + used_bels, type.second, 100*used_bels/type.second); } log_break(); } diff --git a/common/nextpnr.cc b/common/nextpnr.cc index b093d855..144da7c8 100644 --- a/common/nextpnr.cc +++ b/common/nextpnr.cc @@ -53,4 +53,127 @@ void IdString::initialize_add(const BaseCtx *ctx, const char *s, int idx) ctx->idstring_idx_to_str->push_back(&insert_rc.first->first); } +static uint32_t xorshift32(uint32_t x) +{ + x ^= x << 13; + x ^= x >> 17; + x ^= x << 5; + return x; +} + +uint32_t Context::checksum() const +{ + uint32_t cksum = xorshift32(123456789); + + uint32_t cksum_nets_sum = 0; + for (auto &it : nets) + { + auto &ni = *it.second; + uint32_t x = 123456789; + x = xorshift32(x + xorshift32(it.first.index)); + x = xorshift32(x + xorshift32(ni.name.index)); + if (ni.driver.cell) + x = xorshift32(x + xorshift32(ni.driver.cell->name.index)); + x = xorshift32(x + xorshift32(ni.driver.port.index)); + x = xorshift32(x + xorshift32(getDelayChecksum(ni.driver.budget))); + + for (auto &u : ni.users) { + if (u.cell) + x = xorshift32(x + xorshift32(u.cell->name.index)); + x = xorshift32(x + xorshift32(u.port.index)); + x = xorshift32(x + xorshift32(getDelayChecksum(u.budget))); + } + + uint32_t attr_x_sum = 0; + for (auto &a : ni.attrs) { + uint32_t attr_x = 123456789; + attr_x = xorshift32(attr_x + xorshift32(a.first.index)); + for (uint8_t ch : a.second) + attr_x = xorshift32(attr_x + xorshift32(ch)); + attr_x_sum += attr_x; + } + x = xorshift32(x + xorshift32(attr_x_sum)); + + uint32_t wire_x_sum = 0; + for (auto &w : ni.wires) { + uint32_t wire_x = 123456789; + wire_x = xorshift32(wire_x + xorshift32(getWireChecksum(w.first))); + wire_x = xorshift32(wire_x + xorshift32(getPipChecksum(w.second))); + wire_x_sum += wire_x; + } + x = xorshift32(x + xorshift32(wire_x_sum)); + + uint32_t pip_x_sum = 0; + for (auto &p : ni.pips) { + uint32_t pip_x = 123456789; + pip_x = xorshift32(pip_x + xorshift32(getPipChecksum(p.first))); + pip_x = xorshift32(pip_x + xorshift32(p.second)); + pip_x_sum += pip_x; + } + x = xorshift32(x + xorshift32(pip_x_sum)); + + cksum_nets_sum += x; + } + cksum = xorshift32(cksum + xorshift32(cksum_nets_sum)); + + uint32_t cksum_cells_sum = 0; + for (auto &it : cells) + { + auto &ci = *it.second; + uint32_t x = 123456789; + x = xorshift32(x + xorshift32(it.first.index)); + x = xorshift32(x + xorshift32(ci.name.index)); + x = xorshift32(x + xorshift32(ci.type.index)); + + uint32_t port_x_sum = 0; + for (auto &p : ci.ports) { + uint32_t port_x = 123456789; + port_x = xorshift32(port_x + xorshift32(p.first.index)); + port_x = xorshift32(port_x + xorshift32(p.second.name.index)); + if (p.second.net) + port_x = xorshift32(port_x + xorshift32(p.second.net->name.index)); + port_x = xorshift32(port_x + xorshift32(p.second.type)); + port_x_sum += port_x; + } + x = xorshift32(x + xorshift32(port_x_sum)); + + uint32_t attr_x_sum = 0; + for (auto &a : ci.attrs) { + uint32_t attr_x = 123456789; + attr_x = xorshift32(attr_x + xorshift32(a.first.index)); + for (uint8_t ch : a.second) + attr_x = xorshift32(attr_x + xorshift32(ch)); + attr_x_sum += attr_x; + } + x = xorshift32(x + xorshift32(attr_x_sum)); + + uint32_t param_x_sum = 0; + for (auto &p : ci.params) { + uint32_t param_x = 123456789; + param_x = xorshift32(param_x + xorshift32(p.first.index)); + for (uint8_t ch : p.second) + param_x = xorshift32(param_x + xorshift32(ch)); + param_x_sum += param_x; + } + x = xorshift32(x + xorshift32(param_x_sum)); + + x = xorshift32(x + xorshift32(getBelChecksum(ci.bel))); + x = xorshift32(x + xorshift32(ci.belStrength)); + + uint32_t pin_x_sum = 0; + for (auto &a : ci.pins) { + uint32_t pin_x = 123456789; + pin_x = xorshift32(pin_x + xorshift32(a.first.index)); + pin_x = xorshift32(pin_x + xorshift32(a.second.index)); + pin_x_sum += pin_x; + } + x = xorshift32(x + xorshift32(pin_x_sum)); + + cksum_cells_sum += x; + } + cksum = xorshift32(cksum + xorshift32(cksum_cells_sum)); + + return cksum; +} + NEXTPNR_NAMESPACE_END diff --git a/common/nextpnr.h b/common/nextpnr.h index db6901fe..e52f72c2 100644 --- a/common/nextpnr.h +++ b/common/nextpnr.h @@ -302,10 +302,14 @@ struct Context : Arch { // xorshift64star // https://arxiv.org/abs/1402.6246 + + uint64_t retval = rngstate * 0x2545F4914F6CDD1D; + rngstate ^= rngstate >> 12; rngstate ^= rngstate << 25; rngstate ^= rngstate >> 27; - return rngstate * 0x2545F4914F6CDD1D; + + return retval; } int rng() { return rng64() & 0x3fffffff; } @@ -351,6 +355,8 @@ struct Context : Arch std::sort(a.begin(), a.end()); shuffle(a); } + + uint32_t checksum() const; }; NEXTPNR_NAMESPACE_END diff --git a/common/place_sa.cc b/common/place_sa.cc index 591766aa..4d0d5d08 100644 --- a/common/place_sa.cc +++ b/common/place_sa.cc @@ -480,6 +480,7 @@ bool place_design_sa(Context *ctx) { SAPlacer placer(ctx); placer.place(); + log_info("Checksum: 0x%08x\n", ctx->checksum()); return true; } diff --git a/common/route.cc b/common/route.cc index bf11b7d2..69a314d7 100644 --- a/common/route.cc +++ b/common/route.cc @@ -480,6 +480,7 @@ bool route_design(Context *ctx) while (!netsQueue.empty()) { if (iterCnt == 200) { log_warning("giving up after %d iterations.\n", iterCnt); + log_info("Checksum: 0x%08x\n", ctx->checksum()); return false; } @@ -616,6 +617,7 @@ bool route_design(Context *ctx) } log_info("routing complete after %d iterations.\n", iterCnt); + log_info("Checksum: 0x%08x\n", ctx->checksum()); return true; } diff --git a/common/timing.cc b/common/timing.cc index a7b37f9d..ac116711 100644 --- a/common/timing.cc +++ b/common/timing.cc @@ -78,6 +78,7 @@ static delay_t follow_net(Context *ctx, NetInfo *net, int path_length, void assign_budget(Context *ctx, float default_clock) { + log_break(); log_info("Annotating ports with timing budgets\n"); // Clear delays to a very high value first delay_t default_slack = delay_t(1.0e12 / default_clock); @@ -117,6 +118,8 @@ void assign_budget(Context *ctx, float default_clock) net.first.c_str(ctx), ctx->getDelayNS(user.budget)); } } + + log_info("Checksum: 0x%08x\n", ctx->checksum()); } NEXTPNR_NAMESPACE_END diff --git a/dummy/arch.cc b/dummy/arch.cc index 103eee4d..fa9ca473 100644 --- a/dummy/arch.cc +++ b/dummy/arch.cc @@ -34,6 +34,8 @@ BelId Arch::getBelByName(IdString name) const { return BelId(); } IdString Arch::getBelName(BelId bel) const { return IdString(); } +uint32_t Arch::getBelChecksum(BelId bel) const { return 0; } + void Arch::bindBel(BelId bel, IdString cell) {} void Arch::unbindBel(BelId bel) {} @@ -75,6 +77,8 @@ WireId Arch::getWireByName(IdString name) const { return WireId(); } IdString Arch::getWireName(WireId wire) const { return IdString(); } +uint32_t Arch::getWireChecksum(WireId wire) const { return 0; } + void Arch::bindWire(WireId wire, IdString net) {} void Arch::unbindWire(WireId wire) {} @@ -98,6 +102,8 @@ PipId Arch::getPipByName(IdString name) const { return PipId(); } IdString Arch::getPipName(PipId pip) const { return IdString(); } +uint32_t Arch::getWireChecksum(WireId wire) const { return 0; } + void Arch::bindPip(PipId pip, IdString net) {} void Arch::unbindPip(PipId pip) {} diff --git a/dummy/arch.h b/dummy/arch.h index 929c172a..d8068b22 100644 --- a/dummy/arch.h +++ b/dummy/arch.h @@ -87,6 +87,7 @@ struct Arch : BaseCtx BelId getBelByName(IdString name) const; IdString getBelName(BelId bel) const; + uint32_t getBelChecksum(BelId bel) const; void bindBel(BelId bel, IdString cell); void unbindBel(BelId bel); bool checkBelAvail(BelId bel) const; @@ -100,6 +101,7 @@ struct Arch : BaseCtx WireId getWireByName(IdString name) const; IdString getWireName(WireId wire) const; + uint32_t getWireChecksum(WireId wire) const; void bindWire(WireId wire, IdString net); void unbindWire(WireId wire); bool checkWireAvail(WireId wire) const; @@ -108,6 +110,7 @@ struct Arch : BaseCtx PipId getPipByName(IdString name) const; IdString getPipName(PipId pip) const; + uint32_t getPipChecksum(PipId pip) const; void bindPip(PipId pip, IdString net); void unbindPip(PipId pip); bool checkPipAvail(PipId pip) const; @@ -125,6 +128,7 @@ struct Arch : BaseCtx delay_t getDelayEpsilon() const { return 0.01; } delay_t getRipupDelayPenalty() const { return 1.0; } float getDelayNS(delay_t v) const { return v; } + uint32_t getDelayChecksum(delay_t v) const { return 0; } std::vector getFrameGraphics() const; std::vector getBelGraphics(BelId bel) const; diff --git a/frontend/json/jsonparse.cc b/frontend/json/jsonparse.cc index 32ae0953..277e602a 100644 --- a/frontend/json/jsonparse.cc +++ b/frontend/json/jsonparse.cc @@ -828,6 +828,9 @@ void parse_json_file(std::istream *&f, std::string &filename, Context *ctx) { auto *parser = new JsonParser::JsonFrontend(); parser->execute(f, filename, ctx); + + log_info("Checksum: 0x%08x\n", ctx->checksum()); + log_break(); } NEXTPNR_NAMESPACE_END diff --git a/ice40/arch.h b/ice40/arch.h index 4896736b..7778e1c5 100644 --- a/ice40/arch.h +++ b/ice40/arch.h @@ -515,6 +515,11 @@ struct Arch : BaseCtx return id(chip_info->bel_data[bel.index].name.get()); } + uint32_t getBelChecksum(BelId bel) const + { + return bel.index; + } + void bindBel(BelId bel, IdString cell) { assert(bel != BelId()); @@ -607,6 +612,11 @@ struct Arch : BaseCtx return id(chip_info->wire_data[wire.index].name.get()); } + uint32_t getWireChecksum(WireId wire) const + { + return wire.index; + } + void bindWire(WireId wire, IdString net) { assert(wire != WireId()); @@ -646,6 +656,11 @@ struct Arch : BaseCtx PipId getPipByName(IdString name) const; IdString getPipName(PipId pip) const; + uint32_t getPipChecksum(PipId pip) const + { + return pip.index; + } + void bindPip(PipId pip, IdString net) { assert(pip != PipId()); @@ -758,6 +773,7 @@ struct Arch : BaseCtx delay_t getDelayEpsilon() const { return 20; } delay_t getRipupDelayPenalty() const { return 200; } float getDelayNS(delay_t v) const { return v * 0.001; } + uint32_t getDelayChecksum(delay_t v) const { return v; } // ------------------------------------------------- diff --git a/ice40/pack.cc b/ice40/pack.cc index 8a6f1c45..7fcf2750 100644 --- a/ice40/pack.cc +++ b/ice40/pack.cc @@ -487,12 +487,14 @@ static void promote_globals(Context *ctx) // Main pack function bool pack_design(Context *ctx) { + log_break(); pack_constants(ctx); promote_globals(ctx); pack_io(ctx); pack_lut_lutffs(ctx); pack_nonlut_ffs(ctx); pack_ram(ctx); + log_info("Checksum: 0x%08x\n", ctx->checksum()); return true; } -- cgit v1.2.3 From 4fefdbd57c52d6373456bd379e3e54df770e1945 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 21 Jun 2018 16:16:58 +0200 Subject: Cleanup parse_json_file API, some other cleanups Signed-off-by: Clifford Wolf --- common/pybindings.cc | 3 +-- dummy/arch.cc | 2 +- frontend/json/jsonparse.cc | 37 ++++++++++++------------------------- frontend/json/jsonparse.h | 2 +- gui/ice40/worker.cc | 2 +- ice40/main.cc | 2 +- 6 files changed, 17 insertions(+), 31 deletions(-) diff --git a/common/pybindings.cc b/common/pybindings.cc index 26e8bf69..02dc2395 100644 --- a/common/pybindings.cc +++ b/common/pybindings.cc @@ -52,8 +52,7 @@ void parse_json_shim(std::string filename, Context &d) std::ifstream inf(filename); if (!inf) throw std::runtime_error("failed to open file " + filename); - std::istream *ifp = &inf; - parse_json_file(ifp, filename, &d); + parse_json_file(inf, filename, &d); } // Create a new Chip and load design from json file diff --git a/dummy/arch.cc b/dummy/arch.cc index fa9ca473..0ed0f11e 100644 --- a/dummy/arch.cc +++ b/dummy/arch.cc @@ -102,7 +102,7 @@ PipId Arch::getPipByName(IdString name) const { return PipId(); } IdString Arch::getPipName(PipId pip) const { return IdString(); } -uint32_t Arch::getWireChecksum(WireId wire) const { return 0; } +uint32_t Arch::getPipChecksum(PipId wire) const { return 0; } void Arch::bindPip(PipId pip, IdString net) {} diff --git a/frontend/json/jsonparse.cc b/frontend/json/jsonparse.cc index 277e602a..7d9e9dcf 100644 --- a/frontend/json/jsonparse.cc +++ b/frontend/json/jsonparse.cc @@ -795,39 +795,26 @@ void json_import(Context *ctx, string modname, JsonNode *node) } check_all_nets_driven(ctx); } +}; // End Namespace JsonParser -struct JsonFrontend +void parse_json_file(std::istream &f, std::string &filename, Context *ctx) { - // JsonFrontend() : Frontend("json", "read JSON file") { } - JsonFrontend(void) {} - virtual void help() {} - virtual void execute(std::istream *&f, std::string &filename, Context *ctx) - { - // log_header(ctx, "Executing JSON frontend.\n"); + using namespace JsonParser; - JsonNode root(*f); + JsonNode root(f); - if (root.type != 'D') - log_error("JSON root node is not a dictionary.\n"); + if (root.type != 'D') + log_error("JSON root node is not a dictionary.\n"); - if (root.data_dict.count("modules") != 0) { - JsonNode *modules = root.data_dict.at("modules"); + if (root.data_dict.count("modules") != 0) { + JsonNode *modules = root.data_dict.at("modules"); - if (modules->type != 'D') - log_error("JSON modules node is not a dictionary.\n"); + if (modules->type != 'D') + log_error("JSON modules node is not a dictionary.\n"); - for (auto &it : modules->data_dict) - json_import(ctx, it.first, it.second); - } + for (auto &it : modules->data_dict) + json_import(ctx, it.first, it.second); } -}; // JsonFrontend; - -}; // End Namespace JsonParser - -void parse_json_file(std::istream *&f, std::string &filename, Context *ctx) -{ - auto *parser = new JsonParser::JsonFrontend(); - parser->execute(f, filename, ctx); log_info("Checksum: 0x%08x\n", ctx->checksum()); log_break(); diff --git a/frontend/json/jsonparse.h b/frontend/json/jsonparse.h index ee3d19ca..351b6558 100644 --- a/frontend/json/jsonparse.h +++ b/frontend/json/jsonparse.h @@ -26,7 +26,7 @@ NEXTPNR_NAMESPACE_BEGIN -extern void parse_json_file(std::istream *&, std::string &, Context *); +extern void parse_json_file(std::istream &, std::string &, Context *); NEXTPNR_NAMESPACE_END diff --git a/gui/ice40/worker.cc b/gui/ice40/worker.cc index 5a8ff0e9..bd22f552 100644 --- a/gui/ice40/worker.cc +++ b/gui/ice40/worker.cc @@ -18,7 +18,7 @@ Worker::Worker(Context *_ctx) : ctx(_ctx) void Worker::parsejson(const std::string &filename) { std::string fn = filename; - std::istream *f = new std::ifstream(fn); + std::ifstream f(fn); parse_json_file(f, fn, ctx); if (!pack_design(ctx)) diff --git a/ice40/main.cc b/ice40/main.cc index e86cd5b1..76c059b8 100644 --- a/ice40/main.cc +++ b/ice40/main.cc @@ -283,7 +283,7 @@ int main(int argc, char *argv[]) if (vm.count("json")) { std::string filename = vm["json"].as(); - std::istream *f = new std::ifstream(filename); + std::ifstream f(filename); parse_json_file(f, filename, &ctx); -- cgit v1.2.3 From fcfb85e9dc7cc4a858c938692a8612cef3c9538b Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 21 Jun 2018 16:25:25 +0200 Subject: Zero-initialize PortRef budgets Signed-off-by: Clifford Wolf --- common/nextpnr.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/nextpnr.h b/common/nextpnr.h index e52f72c2..1cf0cbbb 100644 --- a/common/nextpnr.h +++ b/common/nextpnr.h @@ -208,7 +208,7 @@ struct PortRef { CellInfo *cell = nullptr; IdString port; - delay_t budget; + delay_t budget = 0; }; struct NetInfo -- cgit v1.2.3 From 54549d36e911aac8d0b0a2eea6074654c06c9717 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Thu, 21 Jun 2018 17:44:18 +0200 Subject: log_error now trows exception, main is covering catch --- common/log.cc | 6 +- common/log.h | 4 + dummy/main.cc | 165 +++++++++-------- gui/basewindow.cc | 1 - gui/basewindow.h | 2 +- gui/dummy/mainwindow.cc | 9 +- gui/dummy/mainwindow.h | 2 +- gui/ice40/mainwindow.cc | 8 +- gui/ice40/worker.cc | 16 +- gui/ice40/worker.h | 18 +- ice40/main.cc | 472 ++++++++++++++++++++++++------------------------ 11 files changed, 355 insertions(+), 348 deletions(-) diff --git a/common/log.cc b/common/log.cc index b0cd802a..495f83b1 100644 --- a/common/log.cc +++ b/common/log.cc @@ -150,12 +150,8 @@ void logv_error(const char *format, va_list ap) #ifdef EMSCRIPTEN log_files = backup_log_files; - throw 0; -#elif defined(_MSC_VER) - _exit(EXIT_FAILURE); -#else - _Exit(EXIT_FAILURE); #endif + throw log_execution_error_exception(); } void log(const char *format, ...) diff --git a/common/log.h b/common/log.h index 381843b3..65b3f178 100644 --- a/common/log.h +++ b/common/log.h @@ -43,6 +43,10 @@ struct log_cmd_error_exception { }; +struct log_execution_error_exception +{ +}; + extern std::vector log_files; extern std::vector log_streams; extern FILE *log_errfile; diff --git a/dummy/main.cc b/dummy/main.cc index cef70235..110c5b6c 100644 --- a/dummy/main.cc +++ b/dummy/main.cc @@ -32,87 +32,96 @@ USING_NEXTPNR_NAMESPACE int main(int argc, char *argv[]) { - namespace po = boost::program_options; - int rc = 0; - - log_files.push_back(stdout); - - po::options_description options("Allowed options"); - options.add_options()("help,h", "show help"); - options.add_options()("verbose,v", "verbose output"); - options.add_options()("force,f", "keep running after errors"); - options.add_options()("gui", "start gui"); - options.add_options()("run", po::value>(), - "python file to execute"); - options.add_options()("version,V", "show version"); - po::positional_options_description pos; - pos.add("run", -1); - - po::variables_map vm; try { - po::parsed_options parsed = po::command_line_parser(argc, argv) - .options(options) - .positional(pos) - .run(); - po::store(parsed, vm); - - po::notify(vm); - } - - catch (std::exception &e) { - std::cout << e.what() << "\n"; - return 1; - } - - if (vm.count("help") || argc == 1) { - std::cout << boost::filesystem::basename(argv[0]) - << " -- Next Generation Place and Route (git " - "sha1 " GIT_COMMIT_HASH_STR ")\n"; - std::cout << "\n"; - std::cout << options << "\n"; - return argc != 1; - } - - if (vm.count("version")) { - std::cout << boost::filesystem::basename(argv[0]) - << " -- Next Generation Place and Route (git " - "sha1 " GIT_COMMIT_HASH_STR ")\n"; - return 1; - } - - Context ctx(ArchArgs{}); - init_python(argv[0]); - python_export_global("ctx", ctx); - - if (vm.count("verbose")) { - ctx.verbose = true; - } - - if (vm.count("force")) { - ctx.force = true; - } - - if (vm.count("seed")) { - ctx.rngseed(vm["seed"].as()); - } - - if (vm.count("run")) { - std::vector files = - vm["run"].as>(); - for (auto filename : files) - execute_python_file(filename.c_str()); - } - - if (vm.count("gui")) { - QApplication a(argc, argv); - MainWindow w(&ctx); - w.show(); - - rc = a.exec(); + namespace po = boost::program_options; + int rc = 0; + + log_files.push_back(stdout); + + po::options_description options("Allowed options"); + options.add_options()("help,h", "show help"); + options.add_options()("verbose,v", "verbose output"); + options.add_options()("force,f", "keep running after errors"); + options.add_options()("gui", "start gui"); + options.add_options()("run", po::value>(), + "python file to execute"); + options.add_options()("version,V", "show version"); + po::positional_options_description pos; + pos.add("run", -1); + + po::variables_map vm; + try { + po::parsed_options parsed = po::command_line_parser(argc, argv) + .options(options) + .positional(pos) + .run(); + + po::store(parsed, vm); + + po::notify(vm); + } + + catch (std::exception &e) { + std::cout << e.what() << "\n"; + return 1; + } + + if (vm.count("help") || argc == 1) { + std::cout << boost::filesystem::basename(argv[0]) + << " -- Next Generation Place and Route (git " + "sha1 " GIT_COMMIT_HASH_STR ")\n"; + std::cout << "\n"; + std::cout << options << "\n"; + return argc != 1; + } + + if (vm.count("version")) { + std::cout << boost::filesystem::basename(argv[0]) + << " -- Next Generation Place and Route (git " + "sha1 " GIT_COMMIT_HASH_STR ")\n"; + return 1; + } + + Context ctx(ArchArgs{}); + init_python(argv[0]); + python_export_global("ctx", ctx); + + if (vm.count("verbose")) { + ctx.verbose = true; + } + + if (vm.count("force")) { + ctx.force = true; + } + + if (vm.count("seed")) { + ctx.rngseed(vm["seed"].as()); + } + + if (vm.count("run")) { + std::vector files = + vm["run"].as>(); + for (auto filename : files) + execute_python_file(filename.c_str()); + } + + if (vm.count("gui")) { + QApplication a(argc, argv); + MainWindow w(&ctx); + w.show(); + + rc = a.exec(); + } + deinit_python(); + return rc; + } catch (log_execution_error_exception) { +#if defined(_MSC_VER) + _exit(EXIT_FAILURE); +#else + _Exit(EXIT_FAILURE); +#endif } - deinit_python(); - return rc; } #endif diff --git a/gui/basewindow.cc b/gui/basewindow.cc index 1e6b171f..9020a719 100644 --- a/gui/basewindow.cc +++ b/gui/basewindow.cc @@ -10,7 +10,6 @@ #include "mainwindow.h" #include "pythontab.h" - BaseMainWindow::BaseMainWindow(Context *_ctx, QWidget *parent) : QMainWindow(parent), ctx(_ctx) { diff --git a/gui/basewindow.h b/gui/basewindow.h index d6915ae9..b20d4621 100644 --- a/gui/basewindow.h +++ b/gui/basewindow.h @@ -30,7 +30,7 @@ class BaseMainWindow : public QMainWindow protected Q_SLOTS: void writeInfo(std::string text); - + virtual void open() = 0; virtual bool save() = 0; diff --git a/gui/dummy/mainwindow.cc b/gui/dummy/mainwindow.cc index f714e30e..7982c5f5 100644 --- a/gui/dummy/mainwindow.cc +++ b/gui/dummy/mainwindow.cc @@ -17,11 +17,6 @@ void MainWindow::createMenu() menuBar->addAction(menu_Custom->menuAction()); } -void MainWindow::open() -{ -} +void MainWindow::open() {} -bool MainWindow::save() -{ - return false; -} \ No newline at end of file +bool MainWindow::save() { return false; } \ No newline at end of file diff --git a/gui/dummy/mainwindow.h b/gui/dummy/mainwindow.h index ea4480fb..c9690f2c 100644 --- a/gui/dummy/mainwindow.h +++ b/gui/dummy/mainwindow.h @@ -19,7 +19,7 @@ class MainWindow : public BaseMainWindow protected Q_SLOTS: virtual void open(); - virtual bool save(); + virtual bool save(); }; #endif // MAINWINDOW_H diff --git a/gui/ice40/mainwindow.cc b/gui/ice40/mainwindow.cc index dafd92e9..934798bb 100644 --- a/gui/ice40/mainwindow.cc +++ b/gui/ice40/mainwindow.cc @@ -20,8 +20,7 @@ MainWindow::MainWindow(Context *_ctx, QWidget *parent) createMenu(); task = new TaskManager(_ctx); - connect(task, SIGNAL(log(std::string)), this, - SLOT(writeInfo(std::string))); + connect(task, SIGNAL(log(std::string)), this, SLOT(writeInfo(std::string))); } MainWindow::~MainWindow() {} @@ -43,7 +42,4 @@ void MainWindow::open() task->parsejson(fn); } } -bool MainWindow::save() -{ - return false; -} \ No newline at end of file +bool MainWindow::save() { return false; } \ No newline at end of file diff --git a/gui/ice40/worker.cc b/gui/ice40/worker.cc index bd22f552..92a0f6ac 100644 --- a/gui/ice40/worker.cc +++ b/gui/ice40/worker.cc @@ -1,13 +1,13 @@ #include "worker.h" #include +#include "bitstream.h" +#include "design_utils.h" #include "jsonparse.h" #include "log.h" #include "pack.h" #include "pcf.h" #include "place_sa.h" #include "route.h" -#include "bitstream.h" -#include "design_utils.h" #include "timing.h" Worker::Worker(Context *_ctx) : ctx(_ctx) @@ -15,7 +15,7 @@ Worker::Worker(Context *_ctx) : ctx(_ctx) log_write_function = [this](std::string text) { Q_EMIT log(text); }; } -void Worker::parsejson(const std::string &filename) +void Worker::parsejson(const std::string &filename) { std::string fn = filename; std::ifstream f(fn); @@ -35,8 +35,7 @@ void Worker::parsejson(const std::string &filename) Q_EMIT log("done"); } - -TaskManager::TaskManager(Context *ctx) +TaskManager::TaskManager(Context *ctx) { Worker *worker = new Worker(ctx); worker->moveToThread(&workerThread); @@ -46,13 +45,10 @@ TaskManager::TaskManager(Context *ctx) workerThread.start(); } -TaskManager::~TaskManager() +TaskManager::~TaskManager() { workerThread.quit(); workerThread.wait(); } -void TaskManager::info(const std::string &result) -{ - Q_EMIT log(result); -} \ No newline at end of file +void TaskManager::info(const std::string &result) { Q_EMIT log(result); } \ No newline at end of file diff --git a/gui/ice40/worker.h b/gui/ice40/worker.h index 5dc25d89..12d740dd 100644 --- a/gui/ice40/worker.h +++ b/gui/ice40/worker.h @@ -1,8 +1,8 @@ #ifndef WORKER_H #define WORKER_H -#include "nextpnr.h" #include +#include "nextpnr.h" // FIXME USING_NEXTPNR_NAMESPACE @@ -10,13 +10,14 @@ USING_NEXTPNR_NAMESPACE class Worker : public QObject { Q_OBJECT -public: + public: Worker(Context *ctx); -public Q_SLOTS: + public Q_SLOTS: void parsejson(const std::string &filename); -Q_SIGNALS: + Q_SIGNALS: void log(const std::string &text); -private: + + private: Context *ctx; }; @@ -24,12 +25,13 @@ class TaskManager : public QObject { Q_OBJECT QThread workerThread; -public: + + public: TaskManager(Context *ctx); ~TaskManager(); -public Q_SLOTS: + public Q_SLOTS: void info(const std::string &text); -Q_SIGNALS: + Q_SIGNALS: void parsejson(const std::string &); void log(const std::string &text); }; diff --git a/ice40/main.cc b/ice40/main.cc index 76c059b8..67d71dc1 100644 --- a/ice40/main.cc +++ b/ice40/main.cc @@ -60,276 +60,286 @@ void svg_dump_el(const GraphicElement &el) int main(int argc, char *argv[]) { - namespace po = boost::program_options; - int rc = 0; - std::string str; - - log_files.push_back(stdout); - - po::options_description options("Allowed options"); - options.add_options()("help,h", "show help"); - options.add_options()("verbose,v", "verbose output"); - options.add_options()("debug", "debug output"); - options.add_options()("force,f", "keep running after errors"); - options.add_options()("gui", "start gui"); - options.add_options()("svg", "dump SVG file"); - options.add_options()("pack-only", - "pack design only without placement or routing"); - - options.add_options()("run", po::value>(), - "python file to execute"); - options.add_options()("json", po::value(), - "JSON design file to ingest"); - options.add_options()("pcf", po::value(), - "PCF constraints file to ingest"); - options.add_options()("asc", po::value(), - "asc bitstream file to write"); - options.add_options()("seed", po::value(), - "seed value for random number generator"); - options.add_options()("version,V", "show version"); - options.add_options()("tmfuzz", "run path delay estimate fuzzer"); - options.add_options()("lp384", "set device type to iCE40LP384"); - options.add_options()("lp1k", "set device type to iCE40LP1K"); - options.add_options()("lp8k", "set device type to iCE40LP8K"); - options.add_options()("hx1k", "set device type to iCE40HX1K"); - options.add_options()("hx8k", "set device type to iCE40HX8K"); - options.add_options()("up5k", "set device type to iCE40UP5K"); - options.add_options()("freq", po::value(), - "set target frequency for design in MHz"); - options.add_options()("package", po::value(), - "set device package"); - po::positional_options_description pos; - pos.add("run", -1); - - po::variables_map vm; try { - po::parsed_options parsed = po::command_line_parser(argc, argv) - .options(options) - .positional(pos) - .run(); - - po::store(parsed, vm); - - po::notify(vm); - } + namespace po = boost::program_options; + int rc = 0; + std::string str; + + log_files.push_back(stdout); + + po::options_description options("Allowed options"); + options.add_options()("help,h", "show help"); + options.add_options()("verbose,v", "verbose output"); + options.add_options()("debug", "debug output"); + options.add_options()("force,f", "keep running after errors"); + options.add_options()("gui", "start gui"); + options.add_options()("svg", "dump SVG file"); + options.add_options()("pack-only", + "pack design only without placement or routing"); + + options.add_options()("run", po::value>(), + "python file to execute"); + options.add_options()("json", po::value(), + "JSON design file to ingest"); + options.add_options()("pcf", po::value(), + "PCF constraints file to ingest"); + options.add_options()("asc", po::value(), + "asc bitstream file to write"); + options.add_options()("seed", po::value(), + "seed value for random number generator"); + options.add_options()("version,V", "show version"); + options.add_options()("tmfuzz", "run path delay estimate fuzzer"); + options.add_options()("lp384", "set device type to iCE40LP384"); + options.add_options()("lp1k", "set device type to iCE40LP1K"); + options.add_options()("lp8k", "set device type to iCE40LP8K"); + options.add_options()("hx1k", "set device type to iCE40HX1K"); + options.add_options()("hx8k", "set device type to iCE40HX8K"); + options.add_options()("up5k", "set device type to iCE40UP5K"); + options.add_options()("freq", po::value(), + "set target frequency for design in MHz"); + options.add_options()("package", po::value(), + "set device package"); + po::positional_options_description pos; + pos.add("run", -1); + + po::variables_map vm; + try { + po::parsed_options parsed = po::command_line_parser(argc, argv) + .options(options) + .positional(pos) + .run(); + + po::store(parsed, vm); + + po::notify(vm); + } - catch (std::exception &e) { - std::cout << e.what() << "\n"; - return 1; - } + catch (std::exception &e) { + std::cout << e.what() << "\n"; + return 1; + } - if (vm.count("help") || argc == 1) { - help: - std::cout << boost::filesystem::basename(argv[0]) - << " -- Next Generation Place and Route (git " - "sha1 " GIT_COMMIT_HASH_STR ")\n"; - std::cout << "\n"; - std::cout << options << "\n"; - return argc != 1; - } + if (vm.count("help") || argc == 1) { + help: + std::cout << boost::filesystem::basename(argv[0]) + << " -- Next Generation Place and Route (git " + "sha1 " GIT_COMMIT_HASH_STR ")\n"; + std::cout << "\n"; + std::cout << options << "\n"; + return argc != 1; + } - if (vm.count("version")) { - std::cout << boost::filesystem::basename(argv[0]) - << " -- Next Generation Place and Route (git " - "sha1 " GIT_COMMIT_HASH_STR ")\n"; - return 1; - } + if (vm.count("version")) { + std::cout << boost::filesystem::basename(argv[0]) + << " -- Next Generation Place and Route (git " + "sha1 " GIT_COMMIT_HASH_STR ")\n"; + return 1; + } - ArchArgs chipArgs; + ArchArgs chipArgs; - if (vm.count("lp384")) { - if (chipArgs.type != ArchArgs::NONE) - goto help; - chipArgs.type = ArchArgs::LP384; - chipArgs.package = "qn32"; - } + if (vm.count("lp384")) { + if (chipArgs.type != ArchArgs::NONE) + goto help; + chipArgs.type = ArchArgs::LP384; + chipArgs.package = "qn32"; + } - if (vm.count("lp1k")) { - if (chipArgs.type != ArchArgs::NONE) - goto help; - chipArgs.type = ArchArgs::LP1K; - chipArgs.package = "tq144"; - } + if (vm.count("lp1k")) { + if (chipArgs.type != ArchArgs::NONE) + goto help; + chipArgs.type = ArchArgs::LP1K; + chipArgs.package = "tq144"; + } - if (vm.count("lp8k")) { - if (chipArgs.type != ArchArgs::NONE) - goto help; - chipArgs.type = ArchArgs::LP8K; - chipArgs.package = "ct256"; - } + if (vm.count("lp8k")) { + if (chipArgs.type != ArchArgs::NONE) + goto help; + chipArgs.type = ArchArgs::LP8K; + chipArgs.package = "ct256"; + } - if (vm.count("hx1k")) { - if (chipArgs.type != ArchArgs::NONE) - goto help; - chipArgs.type = ArchArgs::HX1K; - chipArgs.package = "tq144"; - } + if (vm.count("hx1k")) { + if (chipArgs.type != ArchArgs::NONE) + goto help; + chipArgs.type = ArchArgs::HX1K; + chipArgs.package = "tq144"; + } - if (vm.count("hx8k")) { - if (chipArgs.type != ArchArgs::NONE) - goto help; - chipArgs.type = ArchArgs::HX8K; - chipArgs.package = "ct256"; - } + if (vm.count("hx8k")) { + if (chipArgs.type != ArchArgs::NONE) + goto help; + chipArgs.type = ArchArgs::HX8K; + chipArgs.package = "ct256"; + } - if (vm.count("up5k")) { - if (chipArgs.type != ArchArgs::NONE) - goto help; - chipArgs.type = ArchArgs::UP5K; - chipArgs.package = "sg48"; - } + if (vm.count("up5k")) { + if (chipArgs.type != ArchArgs::NONE) + goto help; + chipArgs.type = ArchArgs::UP5K; + chipArgs.package = "sg48"; + } - if (chipArgs.type == ArchArgs::NONE) { - chipArgs.type = ArchArgs::HX1K; - chipArgs.package = "tq144"; - } + if (chipArgs.type == ArchArgs::NONE) { + chipArgs.type = ArchArgs::HX1K; + chipArgs.package = "tq144"; + } #ifdef ICE40_HX1K_ONLY - if (chipArgs.type != ArchArgs::HX1K) { - std::cout << "This version of nextpnr-ice40 is built with HX1K-support " - "only.\n"; - return 1; - } + if (chipArgs.type != ArchArgs::HX1K) { + std::cout << "This version of nextpnr-ice40 is built with " + "HX1K-support " + "only.\n"; + return 1; + } #endif - if (vm.count("package")) - chipArgs.package = vm["package"].as(); + if (vm.count("package")) + chipArgs.package = vm["package"].as(); - Context ctx(chipArgs); - init_python(argv[0]); - python_export_global("ctx", ctx); + Context ctx(chipArgs); + init_python(argv[0]); + python_export_global("ctx", ctx); - if (vm.count("verbose")) { - ctx.verbose = true; - } - - if (vm.count("debug")) { - ctx.verbose = true; - ctx.debug = true; - } - - if (vm.count("force")) { - ctx.force = true; - } + if (vm.count("verbose")) { + ctx.verbose = true; + } - if (vm.count("seed")) { - ctx.rngseed(vm["seed"].as()); - } + if (vm.count("debug")) { + ctx.verbose = true; + ctx.debug = true; + } - if (vm.count("svg")) { - std::cout << "\n"; - for (auto bel : ctx.getBels()) { - std::cout << "\n"; - for (auto &el : ctx.getBelGraphics(bel)) - svg_dump_el(el); + if (vm.count("force")) { + ctx.force = true; } - std::cout << "\n"; - for (auto &el : ctx.getFrameGraphics()) - svg_dump_el(el); - std::cout << "\n"; - } - if (vm.count("tmfuzz")) { - std::vector src_wires, dst_wires; + if (vm.count("seed")) { + ctx.rngseed(vm["seed"].as()); + } - /*for (auto w : ctx.getWires()) - src_wires.push_back(w);*/ - for (auto b : ctx.getBels()) { - if (ctx.getBelType(b) == TYPE_ICESTORM_LC) { - src_wires.push_back(ctx.getWireBelPin(b, PIN_O)); - } - if (ctx.getBelType(b) == TYPE_SB_IO) { - src_wires.push_back(ctx.getWireBelPin(b, PIN_D_IN_0)); + if (vm.count("svg")) { + std::cout << "\n"; + for (auto bel : ctx.getBels()) { + std::cout << "\n"; + for (auto &el : ctx.getBelGraphics(bel)) + svg_dump_el(el); } + std::cout << "\n"; + for (auto &el : ctx.getFrameGraphics()) + svg_dump_el(el); + std::cout << "\n"; } - for (auto b : ctx.getBels()) { - if (ctx.getBelType(b) == TYPE_ICESTORM_LC) { - dst_wires.push_back(ctx.getWireBelPin(b, PIN_I0)); - dst_wires.push_back(ctx.getWireBelPin(b, PIN_I1)); - dst_wires.push_back(ctx.getWireBelPin(b, PIN_I2)); - dst_wires.push_back(ctx.getWireBelPin(b, PIN_I3)); - dst_wires.push_back(ctx.getWireBelPin(b, PIN_CEN)); - dst_wires.push_back(ctx.getWireBelPin(b, PIN_CIN)); + if (vm.count("tmfuzz")) { + std::vector src_wires, dst_wires; + + /*for (auto w : ctx.getWires()) + src_wires.push_back(w);*/ + for (auto b : ctx.getBels()) { + if (ctx.getBelType(b) == TYPE_ICESTORM_LC) { + src_wires.push_back(ctx.getWireBelPin(b, PIN_O)); + } + if (ctx.getBelType(b) == TYPE_SB_IO) { + src_wires.push_back(ctx.getWireBelPin(b, PIN_D_IN_0)); + } } - if (ctx.getBelType(b) == TYPE_SB_IO) { - dst_wires.push_back(ctx.getWireBelPin(b, PIN_D_OUT_0)); - dst_wires.push_back(ctx.getWireBelPin(b, PIN_OUTPUT_ENABLE)); + + for (auto b : ctx.getBels()) { + if (ctx.getBelType(b) == TYPE_ICESTORM_LC) { + dst_wires.push_back(ctx.getWireBelPin(b, PIN_I0)); + dst_wires.push_back(ctx.getWireBelPin(b, PIN_I1)); + dst_wires.push_back(ctx.getWireBelPin(b, PIN_I2)); + dst_wires.push_back(ctx.getWireBelPin(b, PIN_I3)); + dst_wires.push_back(ctx.getWireBelPin(b, PIN_CEN)); + dst_wires.push_back(ctx.getWireBelPin(b, PIN_CIN)); + } + if (ctx.getBelType(b) == TYPE_SB_IO) { + dst_wires.push_back(ctx.getWireBelPin(b, PIN_D_OUT_0)); + dst_wires.push_back( + ctx.getWireBelPin(b, PIN_OUTPUT_ENABLE)); + } } - } - ctx.shuffle(src_wires); - ctx.shuffle(dst_wires); - - for (int i = 0; i < int(src_wires.size()) && i < int(dst_wires.size()); - i++) { - delay_t actual_delay; - WireId src = src_wires[i], dst = dst_wires[i]; - if (!get_actual_route_delay(&ctx, src, dst, actual_delay)) - continue; - printf("%s %s %.3f %.3f %d %d %d %d %d %d\n", - ctx.getWireName(src).c_str(&ctx), - ctx.getWireName(dst).c_str(&ctx), - ctx.getDelayNS(actual_delay), - ctx.getDelayNS(ctx.estimateDelay(src, dst)), - ctx.chip_info->wire_data[src.index].x, - ctx.chip_info->wire_data[src.index].y, - ctx.chip_info->wire_data[src.index].type, - ctx.chip_info->wire_data[dst.index].x, - ctx.chip_info->wire_data[dst.index].y, - ctx.chip_info->wire_data[dst.index].type); + ctx.shuffle(src_wires); + ctx.shuffle(dst_wires); + + for (int i = 0; + i < int(src_wires.size()) && i < int(dst_wires.size()); i++) { + delay_t actual_delay; + WireId src = src_wires[i], dst = dst_wires[i]; + if (!get_actual_route_delay(&ctx, src, dst, actual_delay)) + continue; + printf("%s %s %.3f %.3f %d %d %d %d %d %d\n", + ctx.getWireName(src).c_str(&ctx), + ctx.getWireName(dst).c_str(&ctx), + ctx.getDelayNS(actual_delay), + ctx.getDelayNS(ctx.estimateDelay(src, dst)), + ctx.chip_info->wire_data[src.index].x, + ctx.chip_info->wire_data[src.index].y, + ctx.chip_info->wire_data[src.index].type, + ctx.chip_info->wire_data[dst.index].x, + ctx.chip_info->wire_data[dst.index].y, + ctx.chip_info->wire_data[dst.index].type); + } } - } - if (vm.count("json")) { - std::string filename = vm["json"].as(); - std::ifstream f(filename); + if (vm.count("json")) { + std::string filename = vm["json"].as(); + std::ifstream f(filename); + parse_json_file(f, filename, &ctx); - parse_json_file(f, filename, &ctx); + if (vm.count("pcf")) { + std::ifstream pcf(vm["pcf"].as()); + apply_pcf(&ctx, pcf); + } - if (vm.count("pcf")) { - std::ifstream pcf(vm["pcf"].as()); - apply_pcf(&ctx, pcf); + if (!pack_design(&ctx) && !ctx.force) + log_error("Packing design failed.\n"); + double freq = 50e6; + if (vm.count("freq")) + freq = vm["freq"].as() * 1e6; + assign_budget(&ctx, freq); + print_utilisation(&ctx); + + if (!vm.count("pack-only")) { + if (!place_design_sa(&ctx) && !ctx.force) + log_error("Placing design failed.\n"); + if (!route_design(&ctx) && !ctx.force) + log_error("Routing design failed.\n"); + } } - if (!pack_design(&ctx) && !ctx.force) - log_error("Packing design failed.\n"); - double freq = 50e6; - if (vm.count("freq")) - freq = vm["freq"].as() * 1e6; - assign_budget(&ctx, freq); - print_utilisation(&ctx); - - if (!vm.count("pack-only")) { - if (!place_design_sa(&ctx) && !ctx.force) - log_error("Placing design failed.\n"); - if (!route_design(&ctx) && !ctx.force) - log_error("Routing design failed.\n"); + if (vm.count("asc")) { + std::string filename = vm["asc"].as(); + std::ofstream f(filename); + write_asc(&ctx, f); } - } - if (vm.count("asc")) { - std::string filename = vm["asc"].as(); - std::ofstream f(filename); - write_asc(&ctx, f); - } - - if (vm.count("run")) { - std::vector files = - vm["run"].as>(); - for (auto filename : files) - execute_python_file(filename.c_str()); - } + if (vm.count("run")) { + std::vector files = + vm["run"].as>(); + for (auto filename : files) + execute_python_file(filename.c_str()); + } - if (vm.count("gui")) { - QApplication a(argc, argv); - MainWindow w(&ctx); - w.show(); + if (vm.count("gui")) { + QApplication a(argc, argv); + MainWindow w(&ctx); + w.show(); - rc = a.exec(); + rc = a.exec(); + } + deinit_python(); + return rc; + } catch (log_execution_error_exception) { +#if defined(_MSC_VER) + _exit(EXIT_FAILURE); +#else + _Exit(EXIT_FAILURE); +#endif } - deinit_python(); - return rc; } #endif -- cgit v1.2.3 From 8fac26c2b795865098b1ba16152cd1c510133f29 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Thu, 21 Jun 2018 17:56:45 +0200 Subject: Fixed return codes for packer, placer and router --- common/place_sa.cc | 12 +- common/route.cc | 332 +++++++++++++++++++++++++++------------------------- gui/ice40/worker.cc | 28 +++-- ice40/pack.cc | 22 ++-- 4 files changed, 207 insertions(+), 187 deletions(-) diff --git a/common/place_sa.cc b/common/place_sa.cc index 4d0d5d08..69ba968f 100644 --- a/common/place_sa.cc +++ b/common/place_sa.cc @@ -478,10 +478,14 @@ class SAPlacer bool place_design_sa(Context *ctx) { - SAPlacer placer(ctx); - placer.place(); - log_info("Checksum: 0x%08x\n", ctx->checksum()); - return true; + try { + SAPlacer placer(ctx); + placer.place(); + log_info("Checksum: 0x%08x\n", ctx->checksum()); + return true; + } catch (log_execution_error_exception) { + return false; + } } NEXTPNR_NAMESPACE_END diff --git a/common/route.cc b/common/route.cc index 69a314d7..e747f09c 100644 --- a/common/route.cc +++ b/common/route.cc @@ -395,230 +395,240 @@ NEXTPNR_NAMESPACE_BEGIN bool route_design(Context *ctx) { - delay_t ripup_penalty = ctx->getRipupDelayPenalty(); - RipupScoreboard scores; - - log_break(); - log_info("Routing..\n"); - - std::unordered_set netsQueue; - - for (auto &net_it : ctx->nets) { - auto net_name = net_it.first; - auto net_info = net_it.second; - - if (net_info->driver.cell == nullptr) - continue; + try { + delay_t ripup_penalty = ctx->getRipupDelayPenalty(); + RipupScoreboard scores; - if (!net_info->wires.empty()) - continue; - - netsQueue.insert(net_name); - } - - if (netsQueue.empty()) { - log_info("found no unrouted nets. no routing necessary.\n"); - return true; - } + log_break(); + log_info("Routing..\n"); - log_info("found %d unrouted nets. starting routing procedure.\n", - int(netsQueue.size())); + std::unordered_set netsQueue; - delay_t estimatedTotalDelay = 0.0; - int estimatedTotalDelayCnt = 0; + for (auto &net_it : ctx->nets) { + auto net_name = net_it.first; + auto net_info = net_it.second; - for (auto net_name : netsQueue) { - auto net_info = ctx->nets.at(net_name); + if (net_info->driver.cell == nullptr) + continue; - auto src_bel = net_info->driver.cell->bel; + if (!net_info->wires.empty()) + continue; - if (src_bel == BelId()) - continue; + netsQueue.insert(net_name); + } - IdString driver_port = net_info->driver.port; + if (netsQueue.empty()) { + log_info("found no unrouted nets. no routing necessary.\n"); + return true; + } - auto driver_port_it = net_info->driver.cell->pins.find(driver_port); - if (driver_port_it != net_info->driver.cell->pins.end()) - driver_port = driver_port_it->second; + log_info("found %d unrouted nets. starting routing procedure.\n", + int(netsQueue.size())); - auto src_wire = - ctx->getWireBelPin(src_bel, ctx->portPinFromId(driver_port)); + delay_t estimatedTotalDelay = 0.0; + int estimatedTotalDelayCnt = 0; - if (src_wire == WireId()) - continue; + for (auto net_name : netsQueue) { + auto net_info = ctx->nets.at(net_name); - for (auto &user_it : net_info->users) { - auto dst_bel = user_it.cell->bel; + auto src_bel = net_info->driver.cell->bel; - if (dst_bel == BelId()) + if (src_bel == BelId()) continue; - IdString user_port = user_it.port; - - auto user_port_it = user_it.cell->pins.find(user_port); + IdString driver_port = net_info->driver.port; - if (user_port_it != user_it.cell->pins.end()) - user_port = user_port_it->second; + auto driver_port_it = net_info->driver.cell->pins.find(driver_port); + if (driver_port_it != net_info->driver.cell->pins.end()) + driver_port = driver_port_it->second; - auto dst_wire = - ctx->getWireBelPin(dst_bel, ctx->portPinFromId(user_port)); + auto src_wire = ctx->getWireBelPin(src_bel, + ctx->portPinFromId(driver_port)); - if (dst_wire == WireId()) + if (src_wire == WireId()) continue; - estimatedTotalDelay += ctx->estimateDelay(src_wire, dst_wire); - estimatedTotalDelayCnt++; - } - } + for (auto &user_it : net_info->users) { + auto dst_bel = user_it.cell->bel; - log_info("estimated total wire delay: %.2f (avg %.2f)\n", - float(estimatedTotalDelay), - float(estimatedTotalDelay) / estimatedTotalDelayCnt); + if (dst_bel == BelId()) + continue; - int iterCnt = 0; + IdString user_port = user_it.port; - while (!netsQueue.empty()) { - if (iterCnt == 200) { - log_warning("giving up after %d iterations.\n", iterCnt); - log_info("Checksum: 0x%08x\n", ctx->checksum()); - return false; - } - - iterCnt++; - if (ctx->verbose) - log_info("-- %d --\n", iterCnt); - - int visitCnt = 0, revisitCnt = 0, netCnt = 0; + auto user_port_it = user_it.cell->pins.find(user_port); - std::unordered_set ripupQueue; + if (user_port_it != user_it.cell->pins.end()) + user_port = user_port_it->second; - if (ctx->verbose || iterCnt == 1) - log_info("routing queue contains %d nets.\n", - int(netsQueue.size())); + auto dst_wire = ctx->getWireBelPin( + dst_bel, ctx->portPinFromId(user_port)); - bool printNets = ctx->verbose && (netsQueue.size() < 10); + if (dst_wire == WireId()) + continue; - std::vector netsArray(netsQueue.begin(), netsQueue.end()); - ctx->sorted_shuffle(netsArray); - netsQueue.clear(); - - for (auto net_name : netsArray) { - if (printNets) - log_info(" routing net %s. (%d users)\n", net_name.c_str(ctx), - int(ctx->nets.at(net_name)->users.size())); + estimatedTotalDelay += ctx->estimateDelay(src_wire, dst_wire); + estimatedTotalDelayCnt++; + } + } - Router router(ctx, scores, net_name, false); + log_info("estimated total wire delay: %.2f (avg %.2f)\n", + float(estimatedTotalDelay), + float(estimatedTotalDelay) / estimatedTotalDelayCnt); - netCnt++; - visitCnt += router.visitCnt; - revisitCnt += router.revisitCnt; + int iterCnt = 0; - if (!router.routedOkay) { - if (printNets) - log_info(" failed to route to %s.\n", - ctx->getWireName(router.failedDest).c_str(ctx)); - ripupQueue.insert(net_name); + while (!netsQueue.empty()) { + if (iterCnt == 200) { + log_warning("giving up after %d iterations.\n", iterCnt); + log_info("Checksum: 0x%08x\n", ctx->checksum()); + return false; } - if ((ctx->verbose || iterCnt == 1) && !printNets && - (netCnt % 100 == 0)) - log_info(" processed %d nets. (%d routed, %d failed)\n", - netCnt, netCnt - int(ripupQueue.size()), - int(ripupQueue.size())); - } - - int normalRouteCnt = netCnt - int(ripupQueue.size()); + iterCnt++; + if (ctx->verbose) + log_info("-- %d --\n", iterCnt); - if ((ctx->verbose || iterCnt == 1) && (netCnt % 100 != 0)) - log_info(" processed %d nets. (%d routed, %d failed)\n", netCnt, - normalRouteCnt, int(ripupQueue.size())); + int visitCnt = 0, revisitCnt = 0, netCnt = 0; - if (ctx->verbose) - log_info(" routing pass visited %d PIPs (%.2f%% revisits).\n", - visitCnt, (100.0 * revisitCnt) / visitCnt); + std::unordered_set ripupQueue; - if (!ripupQueue.empty()) { if (ctx->verbose || iterCnt == 1) - log_info("failed to route %d nets. re-routing in ripup mode.\n", - int(ripupQueue.size())); - - printNets = ctx->verbose && (ripupQueue.size() < 10); + log_info("routing queue contains %d nets.\n", + int(netsQueue.size())); - visitCnt = 0; - revisitCnt = 0; - netCnt = 0; - int ripCnt = 0; + bool printNets = ctx->verbose && (netsQueue.size() < 10); - std::vector ripupArray(ripupQueue.begin(), - ripupQueue.end()); - ctx->sorted_shuffle(ripupArray); + std::vector netsArray(netsQueue.begin(), netsQueue.end()); + ctx->sorted_shuffle(netsArray); + netsQueue.clear(); - for (auto net_name : ripupArray) { + for (auto net_name : netsArray) { if (printNets) log_info(" routing net %s. (%d users)\n", net_name.c_str(ctx), int(ctx->nets.at(net_name)->users.size())); - Router router(ctx, scores, net_name, true, ripup_penalty); + Router router(ctx, scores, net_name, false); netCnt++; visitCnt += router.visitCnt; revisitCnt += router.revisitCnt; - if (!router.routedOkay) - log_error("Net %s is impossible to route.\n", - net_name.c_str(ctx)); - - for (auto it : router.rippedNets) - netsQueue.insert(it); - - if (printNets) { - if (router.rippedNets.size() < 10) { - log_info(" ripped up %d other nets:\n", - int(router.rippedNets.size())); - for (auto n : router.rippedNets) - log_info(" %s (%d users)\n", n.c_str(ctx), - int(ctx->nets.at(n)->users.size())); - } else { - log_info(" ripped up %d other nets.\n", - int(router.rippedNets.size())); - } + if (!router.routedOkay) { + if (printNets) + log_info( + " failed to route to %s.\n", + ctx->getWireName(router.failedDest).c_str(ctx)); + ripupQueue.insert(net_name); } - ripCnt += router.rippedNets.size(); - if ((ctx->verbose || iterCnt == 1) && !printNets && (netCnt % 100 == 0)) - log_info(" routed %d nets, ripped %d nets.\n", netCnt, - ripCnt); + log_info(" processed %d nets. (%d routed, %d failed)\n", + netCnt, netCnt - int(ripupQueue.size()), + int(ripupQueue.size())); } + int normalRouteCnt = netCnt - int(ripupQueue.size()); + if ((ctx->verbose || iterCnt == 1) && (netCnt % 100 != 0)) - log_info(" routed %d nets, ripped %d nets.\n", netCnt, ripCnt); + log_info(" processed %d nets. (%d routed, %d failed)\n", + netCnt, normalRouteCnt, int(ripupQueue.size())); if (ctx->verbose) log_info(" routing pass visited %d PIPs (%.2f%% revisits).\n", visitCnt, (100.0 * revisitCnt) / visitCnt); - if (ctx->verbose && !netsQueue.empty()) - log_info(" ripped up %d previously routed nets. continue " - "routing.\n", - int(netsQueue.size())); - } + if (!ripupQueue.empty()) { + if (ctx->verbose || iterCnt == 1) + log_info("failed to route %d nets. re-routing in ripup " + "mode.\n", + int(ripupQueue.size())); + + printNets = ctx->verbose && (ripupQueue.size() < 10); + + visitCnt = 0; + revisitCnt = 0; + netCnt = 0; + int ripCnt = 0; + + std::vector ripupArray(ripupQueue.begin(), + ripupQueue.end()); + ctx->sorted_shuffle(ripupArray); + + for (auto net_name : ripupArray) { + if (printNets) + log_info(" routing net %s. (%d users)\n", + net_name.c_str(ctx), + int(ctx->nets.at(net_name)->users.size())); + + Router router(ctx, scores, net_name, true, ripup_penalty); + + netCnt++; + visitCnt += router.visitCnt; + revisitCnt += router.revisitCnt; + + if (!router.routedOkay) + log_error("Net %s is impossible to route.\n", + net_name.c_str(ctx)); + + for (auto it : router.rippedNets) + netsQueue.insert(it); + + if (printNets) { + if (router.rippedNets.size() < 10) { + log_info(" ripped up %d other nets:\n", + int(router.rippedNets.size())); + for (auto n : router.rippedNets) + log_info(" %s (%d users)\n", n.c_str(ctx), + int(ctx->nets.at(n)->users.size())); + } else { + log_info(" ripped up %d other nets.\n", + int(router.rippedNets.size())); + } + } - if (!ctx->verbose) - log_info("iteration %d: routed %d nets without ripup, routed %d " - "nets with ripup.\n", - iterCnt, normalRouteCnt, int(ripupQueue.size())); + ripCnt += router.rippedNets.size(); - if (iterCnt == 8 || iterCnt == 16 || iterCnt == 32 || iterCnt == 64 || - iterCnt == 128) - ripup_penalty += ctx->getRipupDelayPenalty(); - } + if ((ctx->verbose || iterCnt == 1) && !printNets && + (netCnt % 100 == 0)) + log_info(" routed %d nets, ripped %d nets.\n", netCnt, + ripCnt); + } + + if ((ctx->verbose || iterCnt == 1) && (netCnt % 100 != 0)) + log_info(" routed %d nets, ripped %d nets.\n", netCnt, + ripCnt); - log_info("routing complete after %d iterations.\n", iterCnt); - log_info("Checksum: 0x%08x\n", ctx->checksum()); - return true; + if (ctx->verbose) + log_info(" routing pass visited %d PIPs (%.2f%% " + "revisits).\n", + visitCnt, (100.0 * revisitCnt) / visitCnt); + + if (ctx->verbose && !netsQueue.empty()) + log_info(" ripped up %d previously routed nets. continue " + "routing.\n", + int(netsQueue.size())); + } + + if (!ctx->verbose) + log_info( + "iteration %d: routed %d nets without ripup, routed %d " + "nets with ripup.\n", + iterCnt, normalRouteCnt, int(ripupQueue.size())); + + if (iterCnt == 8 || iterCnt == 16 || iterCnt == 32 || + iterCnt == 64 || iterCnt == 128) + ripup_penalty += ctx->getRipupDelayPenalty(); + } + + log_info("routing complete after %d iterations.\n", iterCnt); + log_info("Checksum: 0x%08x\n", ctx->checksum()); + return true; + } catch (log_execution_error_exception) { + return false; + } } bool get_actual_route_delay(Context *ctx, WireId src_wire, WireId dst_wire, diff --git a/gui/ice40/worker.cc b/gui/ice40/worker.cc index 92a0f6ac..f86ec55e 100644 --- a/gui/ice40/worker.cc +++ b/gui/ice40/worker.cc @@ -19,20 +19,22 @@ void Worker::parsejson(const std::string &filename) { std::string fn = filename; std::ifstream f(fn); + try { + parse_json_file(f, fn, ctx); + if (!pack_design(ctx)) + log_error("Packing design failed.\n"); + double freq = 50e6; + assign_budget(ctx, freq); + print_utilisation(ctx); - parse_json_file(f, fn, ctx); - if (!pack_design(ctx)) - log_error("Packing design failed.\n"); - double freq = 50e6; - assign_budget(ctx, freq); - print_utilisation(ctx); - - if (!place_design_sa(ctx)) - log_error("Placing design failed.\n"); - if (!route_design(ctx)) - log_error("Routing design failed.\n"); - print_utilisation(ctx); - Q_EMIT log("done"); + if (!place_design_sa(ctx)) + log_error("Placing design failed.\n"); + if (!route_design(ctx)) + log_error("Routing design failed.\n"); + Q_EMIT log("done"); + } catch (log_execution_error_exception) { + Q_EMIT log("failed"); + } } TaskManager::TaskManager(Context *ctx) diff --git a/ice40/pack.cc b/ice40/pack.cc index 7fcf2750..9258014e 100644 --- a/ice40/pack.cc +++ b/ice40/pack.cc @@ -487,15 +487,19 @@ static void promote_globals(Context *ctx) // Main pack function bool pack_design(Context *ctx) { - log_break(); - pack_constants(ctx); - promote_globals(ctx); - pack_io(ctx); - pack_lut_lutffs(ctx); - pack_nonlut_ffs(ctx); - pack_ram(ctx); - log_info("Checksum: 0x%08x\n", ctx->checksum()); - return true; + try { + log_break(); + pack_constants(ctx); + promote_globals(ctx); + pack_io(ctx); + pack_lut_lutffs(ctx); + pack_nonlut_ffs(ctx); + pack_ram(ctx); + log_info("Checksum: 0x%08x\n", ctx->checksum()); + return true; + } catch (log_execution_error_exception) { + return false; + } } NEXTPNR_NAMESPACE_END -- cgit v1.2.3 From c33a039ac388bfcb5e068a04a7cb1b05ebec7d7f Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Thu, 21 Jun 2018 18:08:28 +0200 Subject: Added return code to json parsing and pcf reading --- frontend/json/jsonparse.cc | 33 +++++++++++--------- frontend/json/jsonparse.h | 2 +- gui/ice40/worker.cc | 4 +-- ice40/main.cc | 6 ++-- ice40/pcf.cc | 75 +++++++++++++++++++++++++--------------------- ice40/pcf.h | 2 +- 6 files changed, 68 insertions(+), 54 deletions(-) diff --git a/frontend/json/jsonparse.cc b/frontend/json/jsonparse.cc index 7d9e9dcf..a832e9e5 100644 --- a/frontend/json/jsonparse.cc +++ b/frontend/json/jsonparse.cc @@ -797,27 +797,32 @@ void json_import(Context *ctx, string modname, JsonNode *node) } }; // End Namespace JsonParser -void parse_json_file(std::istream &f, std::string &filename, Context *ctx) +bool parse_json_file(std::istream &f, std::string &filename, Context *ctx) { - using namespace JsonParser; + try { + using namespace JsonParser; - JsonNode root(f); + JsonNode root(f); - if (root.type != 'D') - log_error("JSON root node is not a dictionary.\n"); + if (root.type != 'D') + log_error("JSON root node is not a dictionary.\n"); - if (root.data_dict.count("modules") != 0) { - JsonNode *modules = root.data_dict.at("modules"); + if (root.data_dict.count("modules") != 0) { + JsonNode *modules = root.data_dict.at("modules"); - if (modules->type != 'D') - log_error("JSON modules node is not a dictionary.\n"); + if (modules->type != 'D') + log_error("JSON modules node is not a dictionary.\n"); - for (auto &it : modules->data_dict) - json_import(ctx, it.first, it.second); - } + for (auto &it : modules->data_dict) + json_import(ctx, it.first, it.second); + } - log_info("Checksum: 0x%08x\n", ctx->checksum()); - log_break(); + log_info("Checksum: 0x%08x\n", ctx->checksum()); + log_break(); + return true; + } catch (log_execution_error_exception) { + return false; + } } NEXTPNR_NAMESPACE_END diff --git a/frontend/json/jsonparse.h b/frontend/json/jsonparse.h index 351b6558..fe71444f 100644 --- a/frontend/json/jsonparse.h +++ b/frontend/json/jsonparse.h @@ -26,7 +26,7 @@ NEXTPNR_NAMESPACE_BEGIN -extern void parse_json_file(std::istream &, std::string &, Context *); +extern bool parse_json_file(std::istream &, std::string &, Context *); NEXTPNR_NAMESPACE_END diff --git a/gui/ice40/worker.cc b/gui/ice40/worker.cc index f86ec55e..5702137b 100644 --- a/gui/ice40/worker.cc +++ b/gui/ice40/worker.cc @@ -20,7 +20,8 @@ void Worker::parsejson(const std::string &filename) std::string fn = filename; std::ifstream f(fn); try { - parse_json_file(f, fn, ctx); + if (!parse_json_file(f, fn, ctx)) + log_error("Loading design failed.\n"); if (!pack_design(ctx)) log_error("Packing design failed.\n"); double freq = 50e6; @@ -33,7 +34,6 @@ void Worker::parsejson(const std::string &filename) log_error("Routing design failed.\n"); Q_EMIT log("done"); } catch (log_execution_error_exception) { - Q_EMIT log("failed"); } } diff --git a/ice40/main.cc b/ice40/main.cc index 67d71dc1..067637e8 100644 --- a/ice40/main.cc +++ b/ice40/main.cc @@ -288,11 +288,13 @@ int main(int argc, char *argv[]) if (vm.count("json")) { std::string filename = vm["json"].as(); std::ifstream f(filename); - parse_json_file(f, filename, &ctx); + if (!parse_json_file(f, filename, &ctx)) + log_error("Loading design failed.\n"); if (vm.count("pcf")) { std::ifstream pcf(vm["pcf"].as()); - apply_pcf(&ctx, pcf); + if (!apply_pcf(&ctx, pcf)) + log_error("Loading PCF failed.\n"); } if (!pack_design(&ctx) && !ctx.force) diff --git a/ice40/pcf.cc b/ice40/pcf.cc index 756aba4a..87d27ff1 100644 --- a/ice40/pcf.cc +++ b/ice40/pcf.cc @@ -27,44 +27,51 @@ NEXTPNR_NAMESPACE_BEGIN // Read a w // Apply PCF constraints to a pre-packing design -void apply_pcf(Context *ctx, std::istream &in) +bool apply_pcf(Context *ctx, std::istream &in) { - if (!in) - log_error("failed to open PCF file"); - std::string line; - while (std::getline(in, line)) { - size_t cstart = line.find("#"); - if (cstart != std::string::npos) - line = line.substr(0, cstart); - std::stringstream ss(line); - std::vector words; - std::string tmp; - while (ss >> tmp) - words.push_back(tmp); - if (words.size() == 0) - continue; - std::string cmd = words.at(0); - if (cmd == "set_io") { - size_t args_end = 1; - while (args_end < words.size() && words.at(args_end).at(0) == '-') - args_end++; - std::string cell = words.at(args_end); - std::string pin = words.at(args_end + 1); - auto fnd_cell = ctx->cells.find(cell); - if (fnd_cell == ctx->cells.end()) { - log_warning("unmatched pcf constraint %s\n", cell.c_str()); + try { + if (!in) + log_error("failed to open PCF file"); + std::string line; + while (std::getline(in, line)) { + size_t cstart = line.find("#"); + if (cstart != std::string::npos) + line = line.substr(0, cstart); + std::stringstream ss(line); + std::vector words; + std::string tmp; + while (ss >> tmp) + words.push_back(tmp); + if (words.size() == 0) + continue; + std::string cmd = words.at(0); + if (cmd == "set_io") { + size_t args_end = 1; + while (args_end < words.size() && + words.at(args_end).at(0) == '-') + args_end++; + std::string cell = words.at(args_end); + std::string pin = words.at(args_end + 1); + auto fnd_cell = ctx->cells.find(cell); + if (fnd_cell == ctx->cells.end()) { + log_warning("unmatched pcf constraint %s\n", cell.c_str()); + } else { + BelId pin_bel = ctx->getPackagePinBel(pin); + if (pin_bel == BelId()) + log_error("package does not have a pin named %s\n", + pin.c_str()); + fnd_cell->second->attrs["BEL"] = + ctx->getBelName(pin_bel).str(); + log_info("constrained '%s' to bel '%s'\n", cell.c_str(), + fnd_cell->second->attrs["BEL"].c_str()); + } } else { - BelId pin_bel = ctx->getPackagePinBel(pin); - if (pin_bel == BelId()) - log_error("package does not have a pin named %s\n", - pin.c_str()); - fnd_cell->second->attrs["BEL"] = ctx->getBelName(pin_bel).str(); - log_info("constrained '%s' to bel '%s'\n", cell.c_str(), - fnd_cell->second->attrs["BEL"].c_str()); + log_error("unsupported pcf command '%s'\n", cmd.c_str()); } - } else { - log_error("unsupported pcf command '%s'\n", cmd.c_str()); } + return true; + } catch (log_execution_error_exception) { + return false; } } diff --git a/ice40/pcf.h b/ice40/pcf.h index e0816075..b86a7609 100644 --- a/ice40/pcf.h +++ b/ice40/pcf.h @@ -27,7 +27,7 @@ NEXTPNR_NAMESPACE_BEGIN // Apply PCF constraints to a pre-packing design -void apply_pcf(Context *ctx, std::istream &in); +bool apply_pcf(Context *ctx, std::istream &in); NEXTPNR_NAMESPACE_END -- cgit v1.2.3 From 38dc1cc5504961f666da32d7249532a23d5876ad Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 21 Jun 2018 19:17:04 +0200 Subject: Work "overtime" to find better solutions in routing search algorithm Signed-off-by: Clifford Wolf --- common/route.cc | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/common/route.cc b/common/route.cc index 69a314d7..0c072c3a 100644 --- a/common/route.cc +++ b/common/route.cc @@ -100,7 +100,7 @@ struct Router std::unordered_set rippedNets; std::unordered_map visited; - int visitCnt = 0, revisitCnt = 0; + int visitCnt = 0, revisitCnt = 0, overtimeRevisitCnt = 0; bool routedOkay = false; delay_t maxDelay = 0.0; WireId failedDest; @@ -126,16 +126,22 @@ struct Router visited[qw.wire] = qw; } - while (!queue.empty() && !visited.count(dst_wire)) { + int thisVisitCnt = 0; + int thisVisitCntLimit = 0; + + while (!queue.empty() && (thisVisitCntLimit == 0 || thisVisitCnt < thisVisitCntLimit)) { QueuedWire qw = queue.top(); queue.pop(); + if (thisVisitCntLimit == 0 && visited.count(dst_wire)) + thisVisitCntLimit = (thisVisitCnt*3)/2; + for (auto pip : ctx->getPipsDownhill(qw.wire)) { delay_t next_delay = qw.delay + ctx->getPipDelay(pip).avgDelay(); WireId next_wire = ctx->getPipDstWire(pip); bool foundRipupNet = false; - visitCnt++; + thisVisitCnt++; if (!ctx->checkWireAvail(next_wire)) { if (!ripup) @@ -180,7 +186,10 @@ struct Router ctx->getDelayNS(visited.at(next_wire).delay), ctx->getDelayNS(next_delay)); #endif - revisitCnt++; + if (thisVisitCntLimit == 0) + revisitCnt++; + else + overtimeRevisitCnt++; } QueuedWire next_qw; @@ -194,6 +203,8 @@ struct Router queue.push(next_qw); } } + + visitCnt += thisVisitCnt; } Router(Context *ctx, RipupScoreboard &scores, WireId src_wire, @@ -488,7 +499,7 @@ bool route_design(Context *ctx) if (ctx->verbose) log_info("-- %d --\n", iterCnt); - int visitCnt = 0, revisitCnt = 0, netCnt = 0; + int visitCnt = 0, revisitCnt = 0, overtimeRevisitCnt = 0, netCnt = 0; std::unordered_set ripupQueue; @@ -512,6 +523,7 @@ bool route_design(Context *ctx) netCnt++; visitCnt += router.visitCnt; revisitCnt += router.revisitCnt; + overtimeRevisitCnt += router.overtimeRevisitCnt; if (!router.routedOkay) { if (printNets) @@ -534,8 +546,8 @@ bool route_design(Context *ctx) normalRouteCnt, int(ripupQueue.size())); if (ctx->verbose) - log_info(" routing pass visited %d PIPs (%.2f%% revisits).\n", - visitCnt, (100.0 * revisitCnt) / visitCnt); + log_info(" visited %d PIPs (%.2f%% revisits, %.2f%% overtime revisits).\n", + visitCnt, (100.0 * revisitCnt) / visitCnt, (100.0 * overtimeRevisitCnt) / visitCnt); if (!ripupQueue.empty()) { if (ctx->verbose || iterCnt == 1) @@ -546,6 +558,7 @@ bool route_design(Context *ctx) visitCnt = 0; revisitCnt = 0; + overtimeRevisitCnt = 0; netCnt = 0; int ripCnt = 0; @@ -564,6 +577,7 @@ bool route_design(Context *ctx) netCnt++; visitCnt += router.visitCnt; revisitCnt += router.revisitCnt; + overtimeRevisitCnt += router.overtimeRevisitCnt; if (!router.routedOkay) log_error("Net %s is impossible to route.\n", @@ -597,8 +611,8 @@ bool route_design(Context *ctx) log_info(" routed %d nets, ripped %d nets.\n", netCnt, ripCnt); if (ctx->verbose) - log_info(" routing pass visited %d PIPs (%.2f%% revisits).\n", - visitCnt, (100.0 * revisitCnt) / visitCnt); + log_info(" visited %d PIPs (%.2f%% revisits, %.2f%% overtime revisits).\n", + visitCnt, (100.0 * revisitCnt) / visitCnt, (100.0 * overtimeRevisitCnt) / visitCnt); if (ctx->verbose && !netsQueue.empty()) log_info(" ripped up %d previously routed nets. continue " -- cgit v1.2.3 From 2c98231f88cd145267048b32a5ce0e4deadc2716 Mon Sep 17 00:00:00 2001 From: Clifford Wolf Date: Thu, 21 Jun 2018 19:36:20 +0200 Subject: Updates from clangformat Signed-off-by: Clifford Wolf --- common/design_utils.cc | 4 ++-- common/nextpnr.cc | 9 ++++----- common/route.cc | 20 +++++++++++++------- ice40/arch.h | 15 +++------------ 4 files changed, 22 insertions(+), 26 deletions(-) diff --git a/common/design_utils.cc b/common/design_utils.cc index fa914ee2..92533fa3 100644 --- a/common/design_utils.cc +++ b/common/design_utils.cc @@ -69,8 +69,8 @@ void print_utilisation(const Context *ctx) for (auto type : available_types) { IdString type_id = ctx->belTypeToId(type.first); int used_bels = get_or_default(used_types, type.first, 0); - log_info("\t%20s: %5d/%5d %5d%%\n", type_id.c_str(ctx), - used_bels, type.second, 100*used_bels/type.second); + log_info("\t%20s: %5d/%5d %5d%%\n", type_id.c_str(ctx), used_bels, + type.second, 100 * used_bels / type.second); } log_break(); } diff --git a/common/nextpnr.cc b/common/nextpnr.cc index 144da7c8..b24f66ea 100644 --- a/common/nextpnr.cc +++ b/common/nextpnr.cc @@ -66,8 +66,7 @@ uint32_t Context::checksum() const uint32_t cksum = xorshift32(123456789); uint32_t cksum_nets_sum = 0; - for (auto &it : nets) - { + for (auto &it : nets) { auto &ni = *it.second; uint32_t x = 123456789; x = xorshift32(x + xorshift32(it.first.index)); @@ -117,8 +116,7 @@ uint32_t Context::checksum() const cksum = xorshift32(cksum + xorshift32(cksum_nets_sum)); uint32_t cksum_cells_sum = 0; - for (auto &it : cells) - { + for (auto &it : cells) { auto &ci = *it.second; uint32_t x = 123456789; x = xorshift32(x + xorshift32(it.first.index)); @@ -131,7 +129,8 @@ uint32_t Context::checksum() const port_x = xorshift32(port_x + xorshift32(p.first.index)); port_x = xorshift32(port_x + xorshift32(p.second.name.index)); if (p.second.net) - port_x = xorshift32(port_x + xorshift32(p.second.net->name.index)); + port_x = xorshift32(port_x + + xorshift32(p.second.net->name.index)); port_x = xorshift32(port_x + xorshift32(p.second.type)); port_x_sum += port_x; } diff --git a/common/route.cc b/common/route.cc index e6697349..967f9aa1 100644 --- a/common/route.cc +++ b/common/route.cc @@ -129,12 +129,13 @@ struct Router int thisVisitCnt = 0; int thisVisitCntLimit = 0; - while (!queue.empty() && (thisVisitCntLimit == 0 || thisVisitCnt < thisVisitCntLimit)) { + while (!queue.empty() && + (thisVisitCntLimit == 0 || thisVisitCnt < thisVisitCntLimit)) { QueuedWire qw = queue.top(); queue.pop(); if (thisVisitCntLimit == 0 && visited.count(dst_wire)) - thisVisitCntLimit = (thisVisitCnt*3)/2; + thisVisitCntLimit = (thisVisitCnt * 3) / 2; for (auto pip : ctx->getPipsDownhill(qw.wire)) { delay_t next_delay = @@ -500,7 +501,8 @@ bool route_design(Context *ctx) if (ctx->verbose) log_info("-- %d --\n", iterCnt); - int visitCnt = 0, revisitCnt = 0, overtimeRevisitCnt = 0, netCnt = 0; + int visitCnt = 0, revisitCnt = 0, overtimeRevisitCnt = 0, + netCnt = 0; std::unordered_set ripupQueue; @@ -549,8 +551,10 @@ bool route_design(Context *ctx) netCnt, normalRouteCnt, int(ripupQueue.size())); if (ctx->verbose) - log_info(" visited %d PIPs (%.2f%% revisits, %.2f%% overtime revisits).\n", - visitCnt, (100.0 * revisitCnt) / visitCnt, (100.0 * overtimeRevisitCnt) / visitCnt); + log_info(" visited %d PIPs (%.2f%% revisits, %.2f%% overtime " + "revisits).\n", + visitCnt, (100.0 * revisitCnt) / visitCnt, + (100.0 * overtimeRevisitCnt) / visitCnt); if (!ripupQueue.empty()) { if (ctx->verbose || iterCnt == 1) @@ -616,8 +620,10 @@ bool route_design(Context *ctx) ripCnt); if (ctx->verbose) - log_info(" visited %d PIPs (%.2f%% revisits, %.2f%% overtime revisits).\n", - visitCnt, (100.0 * revisitCnt) / visitCnt, (100.0 * overtimeRevisitCnt) / visitCnt); + log_info(" visited %d PIPs (%.2f%% revisits, %.2f%% " + "overtime revisits).\n", + visitCnt, (100.0 * revisitCnt) / visitCnt, + (100.0 * overtimeRevisitCnt) / visitCnt); if (ctx->verbose && !netsQueue.empty()) log_info(" ripped up %d previously routed nets. continue " diff --git a/ice40/arch.h b/ice40/arch.h index 7778e1c5..f3a46f5c 100644 --- a/ice40/arch.h +++ b/ice40/arch.h @@ -515,10 +515,7 @@ struct Arch : BaseCtx return id(chip_info->bel_data[bel.index].name.get()); } - uint32_t getBelChecksum(BelId bel) const - { - return bel.index; - } + uint32_t getBelChecksum(BelId bel) const { return bel.index; } void bindBel(BelId bel, IdString cell) { @@ -612,10 +609,7 @@ struct Arch : BaseCtx return id(chip_info->wire_data[wire.index].name.get()); } - uint32_t getWireChecksum(WireId wire) const - { - return wire.index; - } + uint32_t getWireChecksum(WireId wire) const { return wire.index; } void bindWire(WireId wire, IdString net) { @@ -656,10 +650,7 @@ struct Arch : BaseCtx PipId getPipByName(IdString name) const; IdString getPipName(PipId pip) const; - uint32_t getPipChecksum(PipId pip) const - { - return pip.index; - } + uint32_t getPipChecksum(PipId pip) const { return pip.index; } void bindPip(PipId pip, IdString net) { -- cgit v1.2.3 From 71176ac5384c696dde1d5601ea1beb5c46f281c6 Mon Sep 17 00:00:00 2001 From: David Shah Date: Fri, 22 Jun 2018 12:34:42 +0200 Subject: Fixing 5k bitstream gen and place heuristics Signed-off-by: David Shah --- common/place_sa.cc | 5 ++--- ice40/bitstream.cc | 13 ++++++++++++- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/common/place_sa.cc b/common/place_sa.cc index 69ba968f..cd4e7282 100644 --- a/common/place_sa.cc +++ b/common/place_sa.cc @@ -410,9 +410,8 @@ class SAPlacer delta = new_wirelength - curr_wirelength; n_move++; // SA acceptance criterea - if (delta < 0 || (temp > 1e-6 && - (ctx->rng() / float(0x3fffffff)) <= - std::exp(-(delta / 2) / temp))) { + if (delta < 0 || (temp > 1e-6 && (ctx->rng() / float(0x3fffffff)) <= + std::exp(-delta / temp))) { n_accept++; if (delta < 2) improved = true; diff --git a/ice40/bitstream.cc b/ice40/bitstream.cc index 8754fef7..e722cea4 100644 --- a/ice40/bitstream.cc +++ b/ice40/bitstream.cc @@ -229,6 +229,16 @@ void write_asc(const Context *ctx, std::ostream &out) set_config(ti, config.at(iey).at(iex), "IoCtrl.REN_" + std::to_string(iez), !pullup); } + + if (ctx->args.type == ArchArgs::UP5K) { + if (iez == 0) { + set_config(ti, config.at(iey).at(iex), "IoCtrl.cf_bit_39", + !pullup); + } else if (iez == 1) { + set_config(ti, config.at(iey).at(iex), "IoCtrl.cf_bit_35", + !pullup); + } + } } else if (cell.second->type == ctx->id("SB_GB")) { // no cell config bits } else if (cell.second->type == ctx->id("ICESTORM_RAM")) { @@ -312,7 +322,8 @@ void write_asc(const Context *ctx, std::ostream &out) ctx->args.type == ArchArgs::HX8K) { setColBufCtrl = (y == 8 || y == 9 || y == 24 || y == 25); } else if (ctx->args.type == ArchArgs::UP5K) { - if (tile == TILE_LOGIC) { + if (tile == TILE_LOGIC || tile == TILE_RAMB || + tile == TILE_RAMT) { setColBufCtrl = (y == 4 || y == 5 || y == 14 || y == 15 || y == 26 || y == 27); } else { -- cgit v1.2.3 From 3cd12e3671e5ee108f039cb4350bf885164a8cf5 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Fri, 22 Jun 2018 12:11:22 +0200 Subject: Add ability to terminate running tasks --- gui/ice40/mainwindow.cc | 14 ++++++++++---- gui/ice40/worker.cc | 42 ++++++++++++++++++++++++++++++++++++------ gui/ice40/worker.h | 13 ++++++++++++- 3 files changed, 58 insertions(+), 11 deletions(-) diff --git a/gui/ice40/mainwindow.cc b/gui/ice40/mainwindow.cc index 934798bb..e36464a0 100644 --- a/gui/ice40/mainwindow.cc +++ b/gui/ice40/mainwindow.cc @@ -17,18 +17,24 @@ MainWindow::MainWindow(Context *_ctx, QWidget *parent) std::string title = "nextpnr-ice40 - " + ctx->getChipName(); setWindowTitle(title.c_str()); - createMenu(); - task = new TaskManager(_ctx); connect(task, SIGNAL(log(std::string)), this, SLOT(writeInfo(std::string))); + + createMenu(); } -MainWindow::~MainWindow() {} +MainWindow::~MainWindow() { delete task; } void MainWindow::createMenu() { QMenu *menu_Custom = new QMenu("&ICE 40", menuBar); menuBar->addAction(menu_Custom->menuAction()); + + QAction *actionTerminate = new QAction("Terminate", this); + actionTerminate->setStatusTip("Terminate running task"); + connect(actionTerminate, SIGNAL(triggered()), task, + SLOT(terminate_thread())); + menu_Custom->addAction(actionTerminate); } void MainWindow::open() @@ -39,7 +45,7 @@ void MainWindow::open() tabWidget->setCurrentWidget(info); std::string fn = fileName.toStdString(); - task->parsejson(fn); + Q_EMIT task->parsejson(fn); } } bool MainWindow::save() { return false; } \ No newline at end of file diff --git a/gui/ice40/worker.cc b/gui/ice40/worker.cc index 5702137b..a309f868 100644 --- a/gui/ice40/worker.cc +++ b/gui/ice40/worker.cc @@ -10,9 +10,19 @@ #include "route.h" #include "timing.h" -Worker::Worker(Context *_ctx) : ctx(_ctx) +struct WorkerInterruptionRequested { - log_write_function = [this](std::string text) { Q_EMIT log(text); }; +}; + +Worker::Worker(Context *_ctx, TaskManager *parent) : ctx(_ctx) +{ + log_write_function = [this, parent](std::string text) { + Q_EMIT log(text); + if (parent->shouldTerminate()) { + parent->clearTerminate(); + throw WorkerInterruptionRequested(); + } + }; } void Worker::parsejson(const std::string &filename) @@ -32,14 +42,16 @@ void Worker::parsejson(const std::string &filename) log_error("Placing design failed.\n"); if (!route_design(ctx)) log_error("Routing design failed.\n"); - Q_EMIT log("done"); + Q_EMIT log("DONE\n"); } catch (log_execution_error_exception) { + } catch (WorkerInterruptionRequested) { + Q_EMIT log("CANCELED\n"); } } -TaskManager::TaskManager(Context *ctx) +TaskManager::TaskManager(Context *ctx) : toTerminate(false) { - Worker *worker = new Worker(ctx); + Worker *worker = new Worker(ctx, this); worker->moveToThread(&workerThread); connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater); connect(this, &TaskManager::parsejson, worker, &Worker::parsejson); @@ -53,4 +65,22 @@ TaskManager::~TaskManager() workerThread.wait(); } -void TaskManager::info(const std::string &result) { Q_EMIT log(result); } \ No newline at end of file +void TaskManager::info(const std::string &result) { Q_EMIT log(result); } + +void TaskManager::terminate_thread() +{ + QMutexLocker locker(&mutex); + toTerminate = true; +} + +bool TaskManager::shouldTerminate() +{ + QMutexLocker locker(&mutex); + return toTerminate; +} + +void TaskManager::clearTerminate() +{ + QMutexLocker locker(&mutex); + toTerminate = false; +} \ No newline at end of file diff --git a/gui/ice40/worker.h b/gui/ice40/worker.h index 12d740dd..a2d220bd 100644 --- a/gui/ice40/worker.h +++ b/gui/ice40/worker.h @@ -1,17 +1,20 @@ #ifndef WORKER_H #define WORKER_H +#include #include #include "nextpnr.h" // FIXME USING_NEXTPNR_NAMESPACE +class TaskManager; + class Worker : public QObject { Q_OBJECT public: - Worker(Context *ctx); + Worker(Context *ctx, TaskManager *parent); public Q_SLOTS: void parsejson(const std::string &filename); Q_SIGNALS: @@ -29,11 +32,19 @@ class TaskManager : public QObject public: TaskManager(Context *ctx); ~TaskManager(); + bool shouldTerminate(); + void clearTerminate(); public Q_SLOTS: void info(const std::string &text); + void terminate_thread(); Q_SIGNALS: + void terminate(); void parsejson(const std::string &); void log(const std::string &text); + + private: + QMutex mutex; + bool toTerminate; }; #endif // WORKER_H -- cgit v1.2.3 From 5cb893aebdfdf711755b9bf610b36b8ff2d942ff Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Fri, 22 Jun 2018 12:24:50 +0200 Subject: terminate on close --- gui/ice40/worker.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gui/ice40/worker.cc b/gui/ice40/worker.cc index a309f868..4b101e7e 100644 --- a/gui/ice40/worker.cc +++ b/gui/ice40/worker.cc @@ -61,6 +61,8 @@ TaskManager::TaskManager(Context *ctx) : toTerminate(false) TaskManager::~TaskManager() { + if (workerThread.isRunning()) + terminate_thread(); workerThread.quit(); workerThread.wait(); } -- cgit v1.2.3 From 11d99853ab4514b1f6b87c5beb87c91f50e702a6 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Fri, 22 Jun 2018 12:49:20 +0200 Subject: more task control --- gui/CMakeLists.txt | 2 +- gui/base.qrc | 8 ++++++++ gui/basewindow.cc | 2 +- gui/dummy/nextpnr.qrc | 2 ++ gui/ice40/mainwindow.cc | 35 ++++++++++++++++++++++++++++++---- gui/ice40/nextpnr.qrc | 7 +++++++ gui/ice40/resources/control_pause.png | Bin 0 -> 598 bytes gui/ice40/resources/control_play.png | Bin 0 -> 592 bytes gui/ice40/resources/control_stop.png | Bin 0 -> 403 bytes gui/ice40/worker.cc | 22 ++++++++++++++++++++- gui/ice40/worker.h | 4 ++++ gui/nextpnr.qrc | 8 -------- 12 files changed, 75 insertions(+), 15 deletions(-) create mode 100644 gui/base.qrc create mode 100644 gui/dummy/nextpnr.qrc create mode 100644 gui/ice40/nextpnr.qrc create mode 100644 gui/ice40/resources/control_pause.png create mode 100644 gui/ice40/resources/control_play.png create mode 100644 gui/ice40/resources/control_stop.png delete mode 100644 gui/nextpnr.qrc diff --git a/gui/CMakeLists.txt b/gui/CMakeLists.txt index b4dcde11..f19d2d20 100644 --- a/gui/CMakeLists.txt +++ b/gui/CMakeLists.txt @@ -3,7 +3,7 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON) aux_source_directory(. GUI_SOURCE_FILES) aux_source_directory(${family}/ GUI_SOURCE_FILES) -set(_RESOURCES nextpnr.qrc) +set(_RESOURCES base.qrc ${family}/nextpnr.qrc) qt5_add_resources(GUI_RESOURCE_FILES ${_RESOURCES}) diff --git a/gui/base.qrc b/gui/base.qrc new file mode 100644 index 00000000..b9e2f237 --- /dev/null +++ b/gui/base.qrc @@ -0,0 +1,8 @@ + + + resources/new.png + resources/open.png + resources/save.png + resources/exit.png + + diff --git a/gui/basewindow.cc b/gui/basewindow.cc index 9020a719..b7258dd3 100644 --- a/gui/basewindow.cc +++ b/gui/basewindow.cc @@ -13,7 +13,7 @@ BaseMainWindow::BaseMainWindow(Context *_ctx, QWidget *parent) : QMainWindow(parent), ctx(_ctx) { - Q_INIT_RESOURCE(nextpnr); + Q_INIT_RESOURCE(base); qRegisterMetaType(); log_files.clear(); diff --git a/gui/dummy/nextpnr.qrc b/gui/dummy/nextpnr.qrc new file mode 100644 index 00000000..03585ec0 --- /dev/null +++ b/gui/dummy/nextpnr.qrc @@ -0,0 +1,2 @@ + + diff --git a/gui/ice40/mainwindow.cc b/gui/ice40/mainwindow.cc index e36464a0..9ce7f41e 100644 --- a/gui/ice40/mainwindow.cc +++ b/gui/ice40/mainwindow.cc @@ -14,6 +14,8 @@ MainWindow::MainWindow(Context *_ctx, QWidget *parent) : BaseMainWindow(_ctx, parent) { + Q_INIT_RESOURCE(nextpnr); + std::string title = "nextpnr-ice40 - " + ctx->getChipName(); setWindowTitle(title.c_str()); @@ -30,11 +32,36 @@ void MainWindow::createMenu() QMenu *menu_Custom = new QMenu("&ICE 40", menuBar); menuBar->addAction(menu_Custom->menuAction()); - QAction *actionTerminate = new QAction("Terminate", this); - actionTerminate->setStatusTip("Terminate running task"); - connect(actionTerminate, SIGNAL(triggered()), task, + QAction *actionPlay = new QAction("Play", this); + QIcon icon1; + icon1.addFile(QStringLiteral(":/icons/resources/control_play.png")); + actionPlay->setIcon(icon1); + actionPlay->setStatusTip("Continue running task"); + connect(actionPlay, SIGNAL(triggered()), task, + SLOT(continue_thread())); + + QAction *actionPause = new QAction("Pause", this); + QIcon icon2; + icon2.addFile(QStringLiteral(":/icons/resources/control_pause.png")); + actionPause->setIcon(icon2); + actionPause->setStatusTip("Pause running task"); + connect(actionPause, SIGNAL(triggered()), task, + SLOT(pause_thread())); + + QAction *actionStop = new QAction("Stop", this); + QIcon icon3; + icon3.addFile(QStringLiteral(":/icons/resources/control_stop.png")); + actionStop->setIcon(icon3); + actionStop->setStatusTip("Stop running task"); + connect(actionStop, SIGNAL(triggered()), task, SLOT(terminate_thread())); - menu_Custom->addAction(actionTerminate); + + QToolBar *taskToolBar = new QToolBar(); + addToolBar(Qt::TopToolBarArea, taskToolBar); + + taskToolBar->addAction(actionPlay); + taskToolBar->addAction(actionPause); + taskToolBar->addAction(actionStop); } void MainWindow::open() diff --git a/gui/ice40/nextpnr.qrc b/gui/ice40/nextpnr.qrc new file mode 100644 index 00000000..cbdb8b26 --- /dev/null +++ b/gui/ice40/nextpnr.qrc @@ -0,0 +1,7 @@ + + + resources/control_play.png + resources/control_pause.png + resources/control_stop.png + + diff --git a/gui/ice40/resources/control_pause.png b/gui/ice40/resources/control_pause.png new file mode 100644 index 00000000..2d9ce9c4 Binary files /dev/null and b/gui/ice40/resources/control_pause.png differ diff --git a/gui/ice40/resources/control_play.png b/gui/ice40/resources/control_play.png new file mode 100644 index 00000000..0846555d Binary files /dev/null and b/gui/ice40/resources/control_play.png differ diff --git a/gui/ice40/resources/control_stop.png b/gui/ice40/resources/control_stop.png new file mode 100644 index 00000000..893bb60e Binary files /dev/null and b/gui/ice40/resources/control_stop.png differ diff --git a/gui/ice40/worker.cc b/gui/ice40/worker.cc index 4b101e7e..3854c67f 100644 --- a/gui/ice40/worker.cc +++ b/gui/ice40/worker.cc @@ -22,6 +22,9 @@ Worker::Worker(Context *_ctx, TaskManager *parent) : ctx(_ctx) parent->clearTerminate(); throw WorkerInterruptionRequested(); } + while (parent->isPaused()){ + QThread::sleep(1); + } }; } @@ -49,7 +52,7 @@ void Worker::parsejson(const std::string &filename) } } -TaskManager::TaskManager(Context *ctx) : toTerminate(false) +TaskManager::TaskManager(Context *ctx) : toTerminate(false), toPause(false) { Worker *worker = new Worker(ctx, this); worker->moveToThread(&workerThread); @@ -85,4 +88,21 @@ void TaskManager::clearTerminate() { QMutexLocker locker(&mutex); toTerminate = false; +} + +void TaskManager::pause_thread() +{ + QMutexLocker locker(&mutex); + toPause = true; +} + +void TaskManager::continue_thread() +{ + QMutexLocker locker(&mutex); + toPause = false; +} +bool TaskManager::isPaused() +{ + QMutexLocker locker(&mutex); + return toPause; } \ No newline at end of file diff --git a/gui/ice40/worker.h b/gui/ice40/worker.h index a2d220bd..49d1df4d 100644 --- a/gui/ice40/worker.h +++ b/gui/ice40/worker.h @@ -34,9 +34,12 @@ class TaskManager : public QObject ~TaskManager(); bool shouldTerminate(); void clearTerminate(); + bool isPaused(); public Q_SLOTS: void info(const std::string &text); void terminate_thread(); + void pause_thread(); + void continue_thread(); Q_SIGNALS: void terminate(); void parsejson(const std::string &); @@ -45,6 +48,7 @@ class TaskManager : public QObject private: QMutex mutex; bool toTerminate; + bool toPause; }; #endif // WORKER_H diff --git a/gui/nextpnr.qrc b/gui/nextpnr.qrc deleted file mode 100644 index b9e2f237..00000000 --- a/gui/nextpnr.qrc +++ /dev/null @@ -1,8 +0,0 @@ - - - resources/new.png - resources/open.png - resources/save.png - resources/exit.png - - -- cgit v1.2.3 From 63baa10032ecf301523e4cb1fca198d8a8b79e23 Mon Sep 17 00:00:00 2001 From: David Shah Date: Fri, 22 Jun 2018 12:57:22 +0200 Subject: ice40: Make the packer deterministic Signed-off-by: David Shah --- common/util.h | 8 ++++++++ ice40/pack.cc | 17 +++++++++-------- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/common/util.h b/common/util.h index 34b2ed02..8151564f 100644 --- a/common/util.h +++ b/common/util.h @@ -21,6 +21,7 @@ #define UTIL_H #include +#include #include "nextpnr.h" NEXTPNR_NAMESPACE_BEGIN @@ -56,6 +57,13 @@ bool bool_or_default(const Container &ct, const KeyType &key, bool def = false) { return bool(int_or_default(ct, key, int(def))); }; + +// Wrap an unordered_map, and allow it to be iterated over sorted by key +template std::map sorted(const std::unordered_map &orig) { + return std::map(orig.begin(), orig.end()); +}; + + NEXTPNR_NAMESPACE_END #endif diff --git a/ice40/pack.cc b/ice40/pack.cc index 9258014e..35cef8b8 100644 --- a/ice40/pack.cc +++ b/ice40/pack.cc @@ -24,6 +24,7 @@ #include "cells.h" #include "design_utils.h" #include "log.h" +#include "util.h" NEXTPNR_NAMESPACE_BEGIN @@ -34,7 +35,7 @@ static void pack_lut_lutffs(Context *ctx) std::unordered_set packed_cells; std::vector new_cells; - for (auto cell : ctx->cells) { + for (auto cell : sorted(ctx->cells)) { CellInfo *ci = cell.second; if (ctx->verbose) log_info("cell '%s' is of type '%s'\n", ci->name.c_str(ctx), @@ -96,7 +97,7 @@ static void pack_nonlut_ffs(Context *ctx) std::unordered_set packed_cells; std::vector new_cells; - for (auto cell : ctx->cells) { + for (auto cell : sorted(ctx->cells)) { CellInfo *ci = cell.second; if (is_ff(ctx, ci)) { CellInfo *packed = create_ice_cell(ctx, "ICESTORM_LC", @@ -126,7 +127,7 @@ static void pack_carries(Context *ctx) std::unordered_set packed_cells; - for (auto cell : ctx->cells) { + for (auto cell : sorted(ctx->cells)) { CellInfo *ci = cell.second; if (is_carry(ctx, ci)) { packed_cells.insert(cell.first); @@ -201,7 +202,7 @@ static void pack_ram(Context *ctx) std::unordered_set packed_cells; std::vector new_cells; - for (auto cell : ctx->cells) { + for (auto cell : sorted(ctx->cells)) { CellInfo *ci = cell.second; if (is_ram(ctx, ci)) { CellInfo *packed = create_ice_cell(ctx, "ICESTORM_RAM", @@ -285,7 +286,7 @@ static void pack_constants(Context *ctx) bool gnd_used = false, vcc_used = false; - for (auto net : ctx->nets) { + for (auto net : sorted(ctx->nets)) { NetInfo *ni = net.second; if (ni->driver.cell != nullptr && ni->driver.cell->type == ctx->id("GND")) { @@ -329,7 +330,7 @@ static void pack_io(Context *ctx) log_info("Packing IOs..\n"); - for (auto cell : ctx->cells) { + for (auto cell : sorted(ctx->cells)) { CellInfo *ci = cell.second; if (is_nextpnr_iob(ctx, ci)) { CellInfo *sb = nullptr; @@ -412,8 +413,8 @@ static void promote_globals(Context *ctx) { log_info("Promoting globals..\n"); - std::unordered_map clock_count, reset_count, cen_count; - for (auto net : ctx->nets) { + std::map clock_count, reset_count, cen_count; + for (auto net : sorted(ctx->nets)) { NetInfo *ni = net.second; if (ni->driver.cell != nullptr && !is_global_net(ctx, ni)) { clock_count[net.first] = 0; -- cgit v1.2.3 From 7f368282700172925428e45f23b8b61e0bf39f94 Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Fri, 22 Jun 2018 13:10:27 +0200 Subject: fixed namespace for gui section --- gui/basewindow.cc | 8 +++++++- gui/basewindow.h | 7 ++++--- gui/designwidget.cc | 4 ++++ gui/designwidget.h | 5 +++-- gui/dummy/mainwindow.cc | 10 +++++++++- gui/dummy/mainwindow.h | 5 +++-- gui/fpgaviewwidget.cc | 4 ++++ gui/fpgaviewwidget.h | 5 +++-- gui/ice40/mainwindow.cc | 22 +++++++++++++--------- gui/ice40/mainwindow.h | 5 +++-- gui/ice40/worker.cc | 10 +++++++--- gui/ice40/worker.h | 5 +++-- gui/infotab.cc | 4 ++++ gui/infotab.h | 5 +++-- gui/line_editor.cc | 7 +++++-- gui/line_editor.h | 5 +++++ gui/pythontab.cc | 6 +++++- gui/pythontab.h | 5 +++-- ice40/main.cc | 2 ++ 19 files changed, 90 insertions(+), 34 deletions(-) diff --git a/gui/basewindow.cc b/gui/basewindow.cc index b7258dd3..f16b205d 100644 --- a/gui/basewindow.cc +++ b/gui/basewindow.cc @@ -10,10 +10,14 @@ #include "mainwindow.h" #include "pythontab.h" +static void initBasenameResource() { Q_INIT_RESOURCE(base); } + +NEXTPNR_NAMESPACE_BEGIN + BaseMainWindow::BaseMainWindow(Context *_ctx, QWidget *parent) : QMainWindow(parent), ctx(_ctx) { - Q_INIT_RESOURCE(base); + initBasenameResource(); qRegisterMetaType(); log_files.clear(); @@ -114,3 +118,5 @@ void BaseMainWindow::createMenusAndBars() mainToolBar->addAction(actionOpen); mainToolBar->addAction(actionSave); } + +NEXTPNR_NAMESPACE_END diff --git a/gui/basewindow.h b/gui/basewindow.h index b20d4621..55e4affc 100644 --- a/gui/basewindow.h +++ b/gui/basewindow.h @@ -11,11 +11,10 @@ #include #include -// FIXME -USING_NEXTPNR_NAMESPACE - Q_DECLARE_METATYPE(std::string) +NEXTPNR_NAMESPACE_BEGIN + class BaseMainWindow : public QMainWindow { Q_OBJECT @@ -45,4 +44,6 @@ class BaseMainWindow : public QMainWindow QStatusBar *statusBar; }; +NEXTPNR_NAMESPACE_END + #endif // BASEMAINWINDOW_H diff --git a/gui/designwidget.cc b/gui/designwidget.cc index 9bb25992..7b1ce543 100644 --- a/gui/designwidget.cc +++ b/gui/designwidget.cc @@ -7,6 +7,8 @@ #include "fpgaviewwidget.h" #include "pybindings.h" +NEXTPNR_NAMESPACE_BEGIN + enum class ElementType { BEL, @@ -234,3 +236,5 @@ void DesignWidget::selectObject() { Q_EMIT info("selected " + itemContextMenu->text(0).toStdString() + "\n"); } + +NEXTPNR_NAMESPACE_END diff --git a/gui/designwidget.h b/gui/designwidget.h index 9682726c..5bd12d4d 100644 --- a/gui/designwidget.h +++ b/gui/designwidget.h @@ -7,8 +7,7 @@ #include "qttreepropertybrowser.h" #include "qtvariantproperty.h" -// FIXME -USING_NEXTPNR_NAMESPACE +NEXTPNR_NAMESPACE_BEGIN class DesignWidget : public QWidget { @@ -45,4 +44,6 @@ class DesignWidget : public QWidget QMap idToProperty; }; +NEXTPNR_NAMESPACE_END + #endif // DESIGNWIDGET_H diff --git a/gui/dummy/mainwindow.cc b/gui/dummy/mainwindow.cc index 7982c5f5..da162dd0 100644 --- a/gui/dummy/mainwindow.cc +++ b/gui/dummy/mainwindow.cc @@ -1,8 +1,14 @@ #include "mainwindow.h" +static void initMainResource() { Q_INIT_RESOURCE(nextpnr); } + +NEXTPNR_NAMESPACE_BEGIN + MainWindow::MainWindow(Context *_ctx, QWidget *parent) : BaseMainWindow(_ctx, parent) { + initMainResource(); + std::string title = "nextpnr-dummy - " + ctx->getChipName(); setWindowTitle(title.c_str()); @@ -19,4 +25,6 @@ void MainWindow::createMenu() void MainWindow::open() {} -bool MainWindow::save() { return false; } \ No newline at end of file +bool MainWindow::save() { return false; } + +NEXTPNR_NAMESPACE_END diff --git a/gui/dummy/mainwindow.h b/gui/dummy/mainwindow.h index c9690f2c..c2786906 100644 --- a/gui/dummy/mainwindow.h +++ b/gui/dummy/mainwindow.h @@ -3,8 +3,7 @@ #include "../basewindow.h" -// FIXME -USING_NEXTPNR_NAMESPACE +NEXTPNR_NAMESPACE_BEGIN class MainWindow : public BaseMainWindow { @@ -22,4 +21,6 @@ class MainWindow : public BaseMainWindow virtual bool save(); }; +NEXTPNR_NAMESPACE_END + #endif // MAINWINDOW_H diff --git a/gui/fpgaviewwidget.cc b/gui/fpgaviewwidget.cc index 6b7e7787..8119eae3 100644 --- a/gui/fpgaviewwidget.cc +++ b/gui/fpgaviewwidget.cc @@ -6,6 +6,8 @@ #include #include "mainwindow.h" +NEXTPNR_NAMESPACE_BEGIN + FPGAViewWidget::FPGAViewWidget(QWidget *parent) : QOpenGLWidget(parent), m_xMove(0), m_yMove(0), m_zDistance(1.0) { @@ -173,3 +175,5 @@ void FPGAViewWidget::wheelEvent(QWheelEvent *event) setZoom(step.y() * -0.1f); } } + +NEXTPNR_NAMESPACE_END diff --git a/gui/fpgaviewwidget.h b/gui/fpgaviewwidget.h index 2407f757..fc3ca562 100644 --- a/gui/fpgaviewwidget.h +++ b/gui/fpgaviewwidget.h @@ -7,8 +7,7 @@ #include #include "nextpnr.h" -// FIXME -USING_NEXTPNR_NAMESPACE +NEXTPNR_NAMESPACE_BEGIN class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions { @@ -49,4 +48,6 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions Context *ctx; }; +NEXTPNR_NAMESPACE_END + #endif diff --git a/gui/ice40/mainwindow.cc b/gui/ice40/mainwindow.cc index 9ce7f41e..4c7bc18f 100644 --- a/gui/ice40/mainwindow.cc +++ b/gui/ice40/mainwindow.cc @@ -11,11 +11,15 @@ #include "place_sa.h" #include "route.h" +static void initMainResource() { Q_INIT_RESOURCE(nextpnr); } + +NEXTPNR_NAMESPACE_BEGIN + MainWindow::MainWindow(Context *_ctx, QWidget *parent) : BaseMainWindow(_ctx, parent) { - Q_INIT_RESOURCE(nextpnr); - + initMainResource(); + std::string title = "nextpnr-ice40 - " + ctx->getChipName(); setWindowTitle(title.c_str()); @@ -37,24 +41,21 @@ void MainWindow::createMenu() icon1.addFile(QStringLiteral(":/icons/resources/control_play.png")); actionPlay->setIcon(icon1); actionPlay->setStatusTip("Continue running task"); - connect(actionPlay, SIGNAL(triggered()), task, - SLOT(continue_thread())); + connect(actionPlay, SIGNAL(triggered()), task, SLOT(continue_thread())); QAction *actionPause = new QAction("Pause", this); QIcon icon2; icon2.addFile(QStringLiteral(":/icons/resources/control_pause.png")); actionPause->setIcon(icon2); actionPause->setStatusTip("Pause running task"); - connect(actionPause, SIGNAL(triggered()), task, - SLOT(pause_thread())); + connect(actionPause, SIGNAL(triggered()), task, SLOT(pause_thread())); QAction *actionStop = new QAction("Stop", this); QIcon icon3; icon3.addFile(QStringLiteral(":/icons/resources/control_stop.png")); actionStop->setIcon(icon3); actionStop->setStatusTip("Stop running task"); - connect(actionStop, SIGNAL(triggered()), task, - SLOT(terminate_thread())); + connect(actionStop, SIGNAL(triggered()), task, SLOT(terminate_thread())); QToolBar *taskToolBar = new QToolBar(); addToolBar(Qt::TopToolBarArea, taskToolBar); @@ -75,4 +76,7 @@ void MainWindow::open() Q_EMIT task->parsejson(fn); } } -bool MainWindow::save() { return false; } \ No newline at end of file + +bool MainWindow::save() { return false; } + +NEXTPNR_NAMESPACE_END \ No newline at end of file diff --git a/gui/ice40/mainwindow.h b/gui/ice40/mainwindow.h index fd65f9ae..712f341a 100644 --- a/gui/ice40/mainwindow.h +++ b/gui/ice40/mainwindow.h @@ -4,8 +4,7 @@ #include "../basewindow.h" #include "worker.h" -// FIXME -USING_NEXTPNR_NAMESPACE +NEXTPNR_NAMESPACE_BEGIN class MainWindow : public BaseMainWindow { @@ -26,4 +25,6 @@ class MainWindow : public BaseMainWindow TaskManager *task; }; +NEXTPNR_NAMESPACE_END + #endif // MAINWINDOW_H diff --git a/gui/ice40/worker.cc b/gui/ice40/worker.cc index 3854c67f..9549f659 100644 --- a/gui/ice40/worker.cc +++ b/gui/ice40/worker.cc @@ -10,6 +10,8 @@ #include "route.h" #include "timing.h" +NEXTPNR_NAMESPACE_BEGIN + struct WorkerInterruptionRequested { }; @@ -22,7 +24,7 @@ Worker::Worker(Context *_ctx, TaskManager *parent) : ctx(_ctx) parent->clearTerminate(); throw WorkerInterruptionRequested(); } - while (parent->isPaused()){ + while (parent->isPaused()) { QThread::sleep(1); } }; @@ -64,7 +66,7 @@ TaskManager::TaskManager(Context *ctx) : toTerminate(false), toPause(false) TaskManager::~TaskManager() { - if (workerThread.isRunning()) + if (workerThread.isRunning()) terminate_thread(); workerThread.quit(); workerThread.wait(); @@ -105,4 +107,6 @@ bool TaskManager::isPaused() { QMutexLocker locker(&mutex); return toPause; -} \ No newline at end of file +} + +NEXTPNR_NAMESPACE_END diff --git a/gui/ice40/worker.h b/gui/ice40/worker.h index 49d1df4d..181fafa3 100644 --- a/gui/ice40/worker.h +++ b/gui/ice40/worker.h @@ -5,8 +5,7 @@ #include #include "nextpnr.h" -// FIXME -USING_NEXTPNR_NAMESPACE +NEXTPNR_NAMESPACE_BEGIN class TaskManager; @@ -51,4 +50,6 @@ class TaskManager : public QObject bool toPause; }; +NEXTPNR_NAMESPACE_END + #endif // WORKER_H diff --git a/gui/infotab.cc b/gui/infotab.cc index 7690b83c..29d557d2 100644 --- a/gui/infotab.cc +++ b/gui/infotab.cc @@ -1,6 +1,8 @@ #include "infotab.h" #include +NEXTPNR_NAMESPACE_BEGIN + InfoTab::InfoTab(QWidget *parent) : QWidget(parent) { plainTextEdit = new QPlainTextEdit(); @@ -37,3 +39,5 @@ void InfoTab::showContextMenu(const QPoint &pt) } void InfoTab::clearBuffer() { plainTextEdit->clear(); } + +NEXTPNR_NAMESPACE_END diff --git a/gui/infotab.h b/gui/infotab.h index d7f1408c..3e0220c4 100644 --- a/gui/infotab.h +++ b/gui/infotab.h @@ -5,8 +5,7 @@ #include #include "nextpnr.h" -// FIXME -USING_NEXTPNR_NAMESPACE +NEXTPNR_NAMESPACE_BEGIN class InfoTab : public QWidget { @@ -24,4 +23,6 @@ class InfoTab : public QWidget QMenu *contextMenu; }; +NEXTPNR_NAMESPACE_END + #endif // INFOTAB_H diff --git a/gui/line_editor.cc b/gui/line_editor.cc index b5ed955f..6299c9cc 100644 --- a/gui/line_editor.cc +++ b/gui/line_editor.cc @@ -1,7 +1,8 @@ #include "line_editor.h" - #include +NEXTPNR_NAMESPACE_BEGIN + LineEditor::LineEditor(QWidget *parent) : QLineEdit(parent), index(0) { setContextMenuPolicy(Qt::CustomContextMenu); @@ -64,4 +65,6 @@ void LineEditor::clearHistory() lines.clear(); index = 0; clear(); -} \ No newline at end of file +} + +NEXTPNR_NAMESPACE_END \ No newline at end of file diff --git a/gui/line_editor.h b/gui/line_editor.h index 15b675f9..5f27e502 100644 --- a/gui/line_editor.h +++ b/gui/line_editor.h @@ -3,6 +3,9 @@ #include #include +#include "nextpnr.h" + +NEXTPNR_NAMESPACE_BEGIN class LineEditor : public QLineEdit { @@ -28,4 +31,6 @@ class LineEditor : public QLineEdit QMenu *contextMenu; }; +NEXTPNR_NAMESPACE_END + #endif // LINE_EDITOR_H diff --git a/gui/pythontab.cc b/gui/pythontab.cc index 96a6c4b9..19aa0162 100644 --- a/gui/pythontab.cc +++ b/gui/pythontab.cc @@ -3,6 +3,8 @@ #include "emb.h" #include "pybindings.h" +NEXTPNR_NAMESPACE_BEGIN + PythonTab::PythonTab(QWidget *parent) : QWidget(parent) { PyImport_ImportModule("emb"); @@ -114,4 +116,6 @@ void PythonTab::showContextMenu(const QPoint &pt) contextMenu->exec(mapToGlobal(pt)); } -void PythonTab::clearBuffer() { plainTextEdit->clear(); } \ No newline at end of file +void PythonTab::clearBuffer() { plainTextEdit->clear(); } + +NEXTPNR_NAMESPACE_END diff --git a/gui/pythontab.h b/gui/pythontab.h index 5aed8b0b..52a8ff8d 100644 --- a/gui/pythontab.h +++ b/gui/pythontab.h @@ -8,8 +8,7 @@ #include "line_editor.h" #include "nextpnr.h" -// FIXME -USING_NEXTPNR_NAMESPACE +NEXTPNR_NAMESPACE_BEGIN class PythonTab : public QWidget { @@ -33,4 +32,6 @@ class PythonTab : public QWidget emb::stdout_write_type write; }; +NEXTPNR_NAMESPACE_END + #endif // PYTHONTAB_H diff --git a/ice40/main.cc b/ice40/main.cc index 067637e8..9e925148 100644 --- a/ice40/main.cc +++ b/ice40/main.cc @@ -38,6 +38,8 @@ #include "timing.h" #include "version.h" +USING_NEXTPNR_NAMESPACE + void svg_dump_el(const GraphicElement &el) { float scale = 10.0, offset = 10.0; -- cgit v1.2.3 From 6633441e32c99d09133e4a62c122a377a4af4ad1 Mon Sep 17 00:00:00 2001 From: David Shah Date: Fri, 22 Jun 2018 13:22:14 +0200 Subject: Update README Signed-off-by: David Shah --- README.md | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 50df309c..751a864b 100644 --- a/README.md +++ b/README.md @@ -11,9 +11,6 @@ Prequisites - CMake 3.3 or later - Modern C++11 compiler (`clang-format` required for development) - - Note: clang may run out of memory building the chipdbs (peak memory - ~11GB) due to the system currently used. Use gcc, or the 1k-only - flag, if this causes a problem. - Qt5 or later (`qt5-default` for Ubuntu 16.04) - Python 3.5 or later, including development libraries (`python3-dev` for Ubuntu) - Boost libraries (`libboost-dev` or `libboost-all-dev` for Ubuntu) @@ -29,8 +26,8 @@ Building - For a release build, run `cmake .` - Add `-DCMAKE_INSTALL_PREFIX=/your/install/prefix` to use a different install prefix to the default `/usr/local` - Use Make to run the build itself - - For all targets, just run `make` - - For just the iCE40 CLI binary, run `make nextpnr-ice40` + - For all binary targets, just run `make` + - For just the iCE40 CLI&GUI binary, run `make nextpnr-ice40` - For just the iCE40 Python module, run `make nextpnrpy_ice40` - Using too many parallel jobs may lead to out-of-memory issues due to the significant memory needed to build the chipdbs - To install nextpnr, run `make install` -- cgit v1.2.3 From ce4ad44fd1837242324ca110a9058182eef99dcd Mon Sep 17 00:00:00 2001 From: David Shah Date: Fri, 22 Jun 2018 14:58:27 +0200 Subject: Print quasi-TNS statistic during placement Signed-off-by: David Shah --- common/place_sa.cc | 24 ++++++++++++++++-------- common/util.h | 7 ++++--- 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/common/place_sa.cc b/common/place_sa.cc index cd4e7282..11f46ad9 100644 --- a/common/place_sa.cc +++ b/common/place_sa.cc @@ -146,8 +146,9 @@ class SAPlacer // Calculate wirelength after initial placement curr_wirelength = 0; + curr_tns = 0; for (auto net : ctx->nets) { - wirelen_t wl = get_wirelength(net.second); + wirelen_t wl = get_wirelength(net.second, curr_tns); wirelengths[net.first] = wl; curr_wirelength += wl; } @@ -162,8 +163,9 @@ class SAPlacer improved = false; if (iter % 5 == 0 || iter == 1) - log_info(" at iteration #%d: temp = %f, wire length = %f\n", - iter, temp, double(curr_wirelength)); + log_info(" at iteration #%d: temp = %.02f, wire length = " + "%.0f, est tns = %.02fns\n", + iter, temp, double(curr_wirelength), curr_tns); for (int m = 0; m < 15; ++m) { // Loop through all automatically placed cells @@ -220,8 +222,9 @@ class SAPlacer // Recalculate total wirelength entirely to avoid rounding errors // accumulating over time curr_wirelength = 0; + curr_tns = 0; for (auto net : ctx->nets) { - wirelen_t wl = get_wirelength(net.second); + wirelen_t wl = get_wirelength(net.second, curr_tns); wirelengths[net.first] = wl; curr_wirelength += wl; } @@ -308,7 +311,7 @@ class SAPlacer } // Get the total estimated wirelength for a net - wirelen_t get_wirelength(NetInfo *net) + wirelen_t get_wirelength(NetInfo *net, float &tns) { wirelen_t wirelength = 0; int driver_x, driver_y; @@ -337,6 +340,8 @@ class SAPlacer delay_t raw_wl = ctx->estimateDelay(drv_wire, user_wire); float slack = ctx->getDelayNS(load.budget) - ctx->getDelayNS(raw_wl); + if (slack < 0) + tns += slack; worst_slack = std::min(slack, worst_slack); int load_x, load_y; bool load_gb; @@ -348,8 +353,9 @@ class SAPlacer xmax = std::max(xmax, load_x); ymax = std::max(ymax, load_y); } - wirelength = wirelen_t((((ymax - ymin) + (xmax - xmin)) * - (1.0 + std::exp(-worst_slack / 5)))); + wirelength = + wirelen_t((((ymax - ymin) + (xmax - xmin)) * + std::min(3.0, (1.0 + std::exp(-worst_slack / 10))))); return wirelength; } @@ -403,7 +409,8 @@ class SAPlacer // Recalculate wirelengths for all nets touched by the peturbation for (auto net : update) { new_wirelength -= wirelengths.at(net->name); - wirelen_t net_new_wl = get_wirelength(net); + float temp_tns = 0; + wirelen_t net_new_wl = get_wirelength(net, temp_tns); new_wirelength += net_new_wl; new_lengths.push_back(std::make_pair(net->name, net_new_wl)); } @@ -465,6 +472,7 @@ class SAPlacer Context *ctx; std::unordered_map wirelengths; wirelen_t curr_wirelength = std::numeric_limits::max(); + float curr_tns = 0; float temp = 1000; bool improved = false; int n_move, n_accept; diff --git a/common/util.h b/common/util.h index 8151564f..4c60292b 100644 --- a/common/util.h +++ b/common/util.h @@ -20,8 +20,8 @@ #ifndef UTIL_H #define UTIL_H -#include #include +#include #include "nextpnr.h" NEXTPNR_NAMESPACE_BEGIN @@ -59,11 +59,12 @@ bool bool_or_default(const Container &ct, const KeyType &key, bool def = false) }; // Wrap an unordered_map, and allow it to be iterated over sorted by key -template std::map sorted(const std::unordered_map &orig) { +template +std::map sorted(const std::unordered_map &orig) +{ return std::map(orig.begin(), orig.end()); }; - NEXTPNR_NAMESPACE_END #endif -- cgit v1.2.3 From d7939f96e6da6eeaffe2d2851f233d32bfb5d6cd Mon Sep 17 00:00:00 2001 From: David Shah Date: Fri, 22 Jun 2018 15:03:33 +0200 Subject: place_sa: Fix temp printing Signed-off-by: David Shah --- common/place_sa.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/place_sa.cc b/common/place_sa.cc index 11f46ad9..8b111c6c 100644 --- a/common/place_sa.cc +++ b/common/place_sa.cc @@ -163,7 +163,7 @@ class SAPlacer improved = false; if (iter % 5 == 0 || iter == 1) - log_info(" at iteration #%d: temp = %.02f, wire length = " + log_info(" at iteration #%d: temp = %f, wire length = " "%.0f, est tns = %.02fns\n", iter, temp, double(curr_wirelength), curr_tns); -- cgit v1.2.3 From f86a0d6c8c8792c36c87cf345665ce7c9fbcc60f Mon Sep 17 00:00:00 2001 From: David Shah Date: Fri, 22 Jun 2018 15:17:00 +0200 Subject: place_sa: Tweak weighting given to timing Signed-off-by: David Shah --- common/place_sa.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/place_sa.cc b/common/place_sa.cc index 8b111c6c..058f0a84 100644 --- a/common/place_sa.cc +++ b/common/place_sa.cc @@ -355,7 +355,7 @@ class SAPlacer } wirelength = wirelen_t((((ymax - ymin) + (xmax - xmin)) * - std::min(3.0, (1.0 + std::exp(-worst_slack / 10))))); + std::min(5.0, (1.0 + std::exp(-worst_slack / 5))))); return wirelength; } -- cgit v1.2.3