From 7142db28a8b828da557729a706c20c8f330ba129 Mon Sep 17 00:00:00 2001 From: David Shah Date: Mon, 25 Feb 2019 11:56:10 +0000 Subject: HeAP: Make HeAP placer optional A CMake option 'BUILD_HEAP' (default on) configures building of the HeAP placer and the associated Eigen3 dependency. Default for the iCE40 is SA placer, with --heap-placer to use HeAP Default for the ECP5 is HeAP placer, as SA placer can take 1hr+ for large ECP5 designs and HeAP tends to give better QoR. --sa-placer can be used to use SA instead, and auto-fallback to SA if HeAP not built. Signed-off-by: David Shah --- CMakeLists.txt | 27 +++++++++++++++++++-------- common/placer_heap.cc | 16 ++++++++++++++++ ecp5/arch.cc | 19 ++++++++++++++++++- ecp5/main.cc | 8 +++++++- ice40/arch.cc | 11 +++++++---- ice40/main.cc | 5 ++++- 6 files changed, 71 insertions(+), 15 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 69089c4c..ade76d60 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,6 +5,8 @@ project(nextpnr) option(BUILD_GUI "Build GUI" ON) option(BUILD_PYTHON "Build Python Integration" ON) option(BUILD_TESTS "Build GUI" OFF) +option(BUILD_HEAP "Build HeAP analytic placer" ON) +option(USE_OPENMP "Use OpenMP to accelerate analytic placer" OFF) option(COVERAGE "Add code coverage info" OFF) option(STATIC_BUILD "Create static build" OFF) option(EXTERNAL_CHIPDB "Create build with pre-built chipdb binaries" OFF) @@ -53,12 +55,16 @@ endforeach() set(CMAKE_CXX_STANDARD 11) if (MSVC) -set(CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING "" FORCE) -set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /D_DEBUG /W4 /wd4100 /wd4244 /wd4125 /wd4800 /wd4456 /wd4458 /wd4305 /wd4459 /wd4121 /wd4996") -set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /W4 /wd4100 /wd4244 /wd4125 /wd4800 /wd4456 /wd4458 /wd4305 /wd4459 /wd4121 /wd4996 /wd4127") + set(CMAKE_CONFIGURATION_TYPES "Debug;Release" CACHE STRING "" FORCE) + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /D_DEBUG /W4 /wd4100 /wd4244 /wd4125 /wd4800 /wd4456 /wd4458 /wd4305 /wd4459 /wd4121 /wd4996") + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /W4 /wd4100 /wd4244 /wd4125 /wd4800 /wd4456 /wd4458 /wd4305 /wd4459 /wd4121 /wd4996 /wd4127") else() -set(CMAKE_CXX_FLAGS_DEBUG "-Wall -fPIC -ggdb -pipe") -set(CMAKE_CXX_FLAGS_RELEASE "-Wall -fPIC -O3 -g -pipe -fopenmp") + set(CMAKE_CXX_FLAGS_DEBUG "-Wall -fPIC -ggdb -pipe") + if (USE_OPENMP) + set(CMAKE_CXX_FLAGS_RELEASE "-Wall -fPIC -O3 -g -pipe -fopenmp") + else() + set(CMAKE_CXX_FLAGS_RELEASE "-Wall -fPIC -O3 -g -pipe") + endif() endif() set(CMAKE_DEFIN) @@ -180,10 +186,15 @@ if (BUILD_PYTHON) endif () endif() -find_package (Eigen3 REQUIRED NO_MODULE) +include_directories(common/ json/ ${Boost_INCLUDE_DIRS} ${PYTHON_INCLUDE_DIRS}) + +if(BUILD_HEAP) + find_package (Eigen3 REQUIRED NO_MODULE) + include_directories(${EIGEN3_INCLUDE_DIRS}) + add_definitions(${EIGEN3_DEFINITIONS}) + add_definitions(-DWITH_HEAP) +endif() -include_directories(common/ json/ ${Boost_INCLUDE_DIRS} ${PYTHON_INCLUDE_DIRS} ${EIGEN3_INCLUDE_DIRS}) -add_definitions(${EIGEN3_DEFINITIONS}) aux_source_directory(common/ COMMON_SRC_FILES) aux_source_directory(json/ JSON_PARSER_FILES) set(COMMON_FILES ${COMMON_SRC_FILES} ${JSON_PARSER_FILES}) diff --git a/common/placer_heap.cc b/common/placer_heap.cc index b6913473..255a3f54 100644 --- a/common/placer_heap.cc +++ b/common/placer_heap.cc @@ -31,6 +31,8 @@ * - To make the placer timing-driven, the bound2bound weights are multiplied by (1 + 10 * crit^2) */ +#ifdef WITH_HEAP + #include #include #include @@ -1509,5 +1511,19 @@ class HeAPPlacer int HeAPPlacer::CutSpreader::seq = 0; bool placer_heap(Context *ctx) { return HeAPPlacer(ctx).place(); } +NEXTPNR_NAMESPACE_END + +#else + +#include "log.h" +#include "nextpnr.h" +NEXTPNR_NAMESPACE_BEGIN +bool placer_heap(Context *ctx) +{ + log_error("nextpnr was built without the HeAP placer\n"); + return false; +} NEXTPNR_NAMESPACE_END + +#endif diff --git a/ecp5/arch.cc b/ecp5/arch.cc index 5ea6a7c3..8385e57b 100644 --- a/ecp5/arch.cc +++ b/ecp5/arch.cc @@ -457,6 +457,7 @@ delay_t Arch::estimateDelay(WireId src, WireId dst) const auto src_loc = est_location(src), dst_loc = est_location(dst); int dx = abs(src_loc.first - dst_loc.first), dy = abs(src_loc.second - dst_loc.second); + return (130 - 25 * args.speed) * (6 + std::max(dx - 5, 0) + std::max(dy - 5, 0) + 2 * (std::min(dx, 5) + std::min(dy, 5))); @@ -486,6 +487,7 @@ delay_t Arch::predictDelay(const NetInfo *net_info, const PortRef &sink) const } int dx = abs(driver_loc.x - sink_loc.x), dy = abs(driver_loc.y - sink_loc.y); + return (130 - 25 * args.speed) * (6 + std::max(dx - 5, 0) + std::max(dy - 5, 0) + 2 * (std::min(dx, 5) + std::min(dy, 5))); } @@ -505,7 +507,22 @@ bool Arch::getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay // ----------------------------------------------------------------------- -bool Arch::place() { return placer_heap(getCtx()); } +bool Arch::place() +{ + // HeAP is the default unless overriden or not built +#ifdef WITH_HEAP + if (bool_or_default(settings, id("sa_placer"), false)) { +#endif + if (!placer1(getCtx(), Placer1Cfg(getCtx()))) + return false; +#ifdef WITH_HEAP + } else { + if (!placer_heap(getCtx())) + return false; + } +#endif + return true; +} bool Arch::route() { diff --git a/ecp5/main.cc b/ecp5/main.cc index 15027a5a..de279e63 100644 --- a/ecp5/main.cc +++ b/ecp5/main.cc @@ -59,6 +59,8 @@ po::options_description ECP5CommandHandler::getArchOptions() specific.add_options()("um5g-45k", "set device type to LFE5UM5G-45F"); specific.add_options()("um5g-85k", "set device type to LFE5UM5G-85F"); + specific.add_options()("sa-placer", "use pure simulated annealing placer instead of HeAP analytic placer"); + specific.add_options()("package", po::value(), "select device package (defaults to CABGA381)"); specific.add_options()("speed", po::value(), "select device speedgrade (6, 7 or 8)"); @@ -149,8 +151,12 @@ std::unique_ptr ECP5CommandHandler::createContext() chipArgs.speed = ArchArgs::SPEED_6; } } + auto ctx = std::unique_ptr(new Context(chipArgs)); + + if (vm.count("sa-placer")) + ctx->settings[ctx->id("sa_placer")] = "1"; - return std::unique_ptr(new Context(chipArgs)); + return ctx; } void ECP5CommandHandler::customAfterLoad(Context *ctx) diff --git a/ice40/arch.cc b/ice40/arch.cc index 5688b6e6..09e64b16 100644 --- a/ice40/arch.cc +++ b/ice40/arch.cc @@ -671,10 +671,13 @@ bool Arch::getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay bool Arch::place() { - // if (!placer1(getCtx(), Placer1Cfg(getCtx()))) - // return false; - if (!placer_heap(getCtx())) - return false; + if (bool_or_default(settings, id("heap_placer"), false)) { + if (!placer_heap(getCtx())) + return false; + } else { + if (!placer1(getCtx(), Placer1Cfg(getCtx()))) + return false; + } if (bool_or_default(settings, id("opt_timing"), false)) { TimingOptCfg tocfg(getCtx()); tocfg.cellTypes.insert(id_ICESTORM_LC); diff --git a/ice40/main.cc b/ice40/main.cc index 2313c2ae..7233f169 100644 --- a/ice40/main.cc +++ b/ice40/main.cc @@ -69,6 +69,8 @@ po::options_description Ice40CommandHandler::getArchOptions() specific.add_options()("promote-logic", "enable promotion of 'logic' globals (in addition to clk/ce/sr by default)"); specific.add_options()("no-promote-globals", "disable all global promotion"); + specific.add_options()("heap-placer", + "use HeAP analytic placer instead of simulated annealing (faster, experimental)"); specific.add_options()("opt-timing", "run post-placement timing optimisation pass (experimental)"); specific.add_options()("tmfuzz", "run path delay estimate fuzzer"); specific.add_options()("pcf-allow-unconstrained", "don't require PCF to constrain all IO"); @@ -176,7 +178,8 @@ std::unique_ptr Ice40CommandHandler::createContext() ctx->settings[ctx->id("opt_timing")] = "1"; if (vm.count("pcf-allow-unconstrained")) ctx->settings[ctx->id("pcf_allow_unconstrained")] = "1"; - + if (vm.count("heap-placer")) + ctx->settings[ctx->id("heap_placer")] = "1"; return ctx; } -- cgit v1.2.3