HeAP: Add TAUCS wrapper and integration

Signed-off-by: David Shah <dave@ds0.me>
This commit is contained in:
David Shah 2019-01-10 16:42:29 +00:00
parent e36460b83e
commit ea56dc9d08
7 changed files with 175 additions and 6 deletions

View File

@ -122,6 +122,8 @@ configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/common/version.h.in ${CMAKE_CURRENT_BINARY_DIR}/generated/version.h ${CMAKE_CURRENT_SOURCE_DIR}/common/version.h.in ${CMAKE_CURRENT_BINARY_DIR}/generated/version.h
) )
add_subdirectory(3rdparty/taucs ${CMAKE_CURRENT_BINARY_DIR}/generated/taucs EXCLUDE_FROM_ALL)
if (BUILD_PYTHON) if (BUILD_PYTHON)
# Find Boost::Python of a suitable version in a cross-platform way # Find Boost::Python of a suitable version in a cross-platform way
# Some distributions (Arch) call it libboost_python3, others such as Ubuntu # Some distributions (Arch) call it libboost_python3, others such as Ubuntu
@ -180,7 +182,7 @@ if (BUILD_PYTHON)
endif () endif ()
endif() endif()
include_directories(common/ json/ ${Boost_INCLUDE_DIRS} ${PYTHON_INCLUDE_DIRS}) include_directories(common/ json/ ${Boost_INCLUDE_DIRS} ${PYTHON_INCLUDE_DIRS} 3rdparty/taucs/src ${CMAKE_CURRENT_BINARY_DIR}/generated/taucs/build/linux)
aux_source_directory(common/ COMMON_SRC_FILES) aux_source_directory(common/ COMMON_SRC_FILES)
aux_source_directory(json/ JSON_PARSER_FILES) aux_source_directory(json/ JSON_PARSER_FILES)
set(COMMON_FILES ${COMMON_SRC_FILES} ${JSON_PARSER_FILES}) set(COMMON_FILES ${COMMON_SRC_FILES} ${JSON_PARSER_FILES})
@ -244,7 +246,7 @@ foreach (family ${ARCH})
# Include family-specific source files to all family targets and set defines appropriately # Include family-specific source files to all family targets and set defines appropriately
target_include_directories(${target} PRIVATE ${family}/ ${CMAKE_CURRENT_BINARY_DIR}/generated/) target_include_directories(${target} PRIVATE ${family}/ ${CMAKE_CURRENT_BINARY_DIR}/generated/)
target_compile_definitions(${target} PRIVATE NEXTPNR_NAMESPACE=nextpnr_${family} ARCH_${ufamily} ARCHNAME=${family}) target_compile_definitions(${target} PRIVATE NEXTPNR_NAMESPACE=nextpnr_${family} ARCH_${ufamily} ARCHNAME=${family})
target_link_libraries(${target} LINK_PUBLIC ${Boost_LIBRARIES} ${link_param}) target_link_libraries(${target} LINK_PUBLIC ${Boost_LIBRARIES} taucs ${link_param})
if (NOT MSVC) if (NOT MSVC)
target_link_libraries(${target} LINK_PUBLIC pthread) target_link_libraries(${target} LINK_PUBLIC pthread)
endif() endif()

View File

@ -25,12 +25,13 @@
*/ */
#include <deque> #include <deque>
#include <numeric>
#include <unordered_map> #include <unordered_map>
#include "log.h" #include "log.h"
#include "nextpnr.h" #include "nextpnr.h"
#include "place_common.h" #include "place_common.h"
#include "placer_math.h"
#include "util.h" #include "util.h"
NEXTPNR_NAMESPACE_BEGIN NEXTPNR_NAMESPACE_BEGIN
namespace { namespace {
@ -76,13 +77,44 @@ template <typename T> struct EquationSystem
} }
void add_rhs(int row, T val) { rhs[row] += val; } void add_rhs(int row, T val) { rhs[row] += val; }
void solve(std::vector<double> &x)
{
int nnz = std::accumulate(A.begin(), A.end(), 0,
[](int a, const std::vector<std::pair<int, T>> &vec) { return a + int(vec.size()); });
taucif_system *sys = taucif_create_system(int(rhs.size()), int(A.size()), nnz);
for (int col = 0; col < int(A.size()); col++) {
auto &Ac = A[col];
for (auto &el : Ac) {
if (col <= el.first)
taucif_set_matrix_value(sys, el.first, col, el.second);
// FIXME: in debug mode, assert really is symmetric
}
}
taucif_solve_system(sys, x.data(), rhs.data());
taucif_free_system(sys);
}
}; };
} // namespace } // namespace
class HeAPPlacer class HeAPPlacer
{ {
public: public:
HeAPPlacer(Context *ctx) : ctx(ctx) {} HeAPPlacer(Context *ctx) : ctx(ctx) {}
bool place()
{
taucif_init_solver();
place_constraints();
build_fast_bels();
seed_placement();
update_all_chains();
EquationSystem<double> es(place_cells.size(), place_cells.size());
build_equations(es, false);
solve_equations(es, false);
return true;
}
private: private:
Context *ctx; Context *ctx;
@ -361,6 +393,19 @@ class HeAPPlacer
}); });
} }
} }
// Build the system of equations for either X or Y
void solve_equations(EquationSystem<double> &es, bool yaxis)
{
// Return the x or y position of a cell, depending on ydir
auto cell_pos = [&](CellInfo *cell) { return yaxis ? cell_locs.at(cell->name).y : cell_locs.at(cell->name).x; };
build_equations(es, yaxis);
std::vector<double> vals;
std::transform(place_cells.begin(), place_cells.end(), std::back_inserter(vals), cell_pos);
es.solve(vals);
}
}; };
bool placer_heap(Context *ctx) { return HeAPPlacer(ctx).place(); }
NEXTPNR_NAMESPACE_END NEXTPNR_NAMESPACE_END

34
common/placer_heap.h Normal file
View File

@ -0,0 +1,34 @@
/*
* nextpnr -- Next Generation Place and Route
*
* Copyright (C) 2019 David Shah <david@symbioticeda.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* [[cite]] HeAP
* Analytical Placement for Heterogeneous FPGAs, Marcel Gort and Jason H. Anderson
* https://janders.eecg.utoronto.ca/pdfs/marcelfpl12.pdf
*
* [[cite]] SimPL
* SimPL: An Effective Placement Algorithm, Myung-Chul Kim, Dong-Jin Lee and Igor L. Markov
* http://www.ece.umich.edu/cse/awards/pdfs/iccad10-simpl.pdf
*/
#ifndef PLACER_HEAP_H
#define PLACER_HEAP
#include "nextpnr.h"
NEXTPNR_NAMESPACE_BEGIN
extern bool placer_heap(Context *ctx);
NEXTPNR_NAMESPACE_END
#endif

43
common/placer_math.c Normal file
View File

@ -0,0 +1,43 @@
#include "taucs.h"
#include "placer_math.h"
#include <stdio.h>
void taucif_init_solver() {
taucs_logfile("stdout");
}
struct taucif_system {
taucs_ccs_matrix* mat;
int ccs_i, ccs_col;
};
struct taucif_system *taucif_create_system(int rows, int cols, int n_nonzero) {
struct taucif_system *sys = taucs_malloc(sizeof(struct taucif_system));
sys->mat = taucs_ccs_create(cols, rows, n_nonzero, TAUCS_DOUBLE | TAUCS_SYMMETRIC);
// Internal pointers
sys->ccs_i = 0;
sys->ccs_col = -1;
return sys;
};
void taucif_set_matrix_value(struct taucif_system *sys, int row, int col, double value) {
while(sys->ccs_col < col) {
sys->mat->colptr[++sys->ccs_col] = sys->ccs_i;
}
sys->mat->rowind[sys->ccs_i] = row;
sys->mat->values.d[sys->ccs_i++] = value;
}
void taucif_solve_system(struct taucif_system *sys, double *x, double *rhs) {
// FIXME: preconditioner, droptol??
taucs_ccs_matrix* precond_mat = taucs_ccs_factor_llt(sys->mat, 1e-3, 0);
// FIXME: itermax, convergetol
int cjres = taucs_conjugate_gradients(sys->mat, taucs_ccs_solve_llt, precond_mat, x, rhs, 1000, 1e-6);
taucs_ccs_free(precond_mat);
}
void taucif_free_system(struct taucif_system *sys) {
taucs_ccs_free(sys->mat);
taucs_free(sys->mat);
}

43
common/placer_math.h Normal file
View File

@ -0,0 +1,43 @@
/*
* nextpnr -- Next Generation Place and Route
*
* Copyright (C) 2019 David Shah <david@symbioticeda.com>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef PLACER_MATH_H
#define PLACER_MATH_H
// This shim is needed because Tauc is mutually incompatible with modern C++ (implementing macros and functions
// that collide with max, min, etc)
#ifdef __cplusplus
extern "C" {
#endif
extern void taucif_init_solver();
struct taucif_system;
extern struct taucif_system *taucif_create_system(int rows, int cols, int n_nonzero);
extern void taucif_set_matrix_value(struct taucif_system *sys, int row, int col, double value);
extern void taucif_solve_system(struct taucif_system *sys, double *x, double *rhs);
extern void taucif_free_system(struct taucif_system *sys);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -458,6 +458,7 @@ delay_t Arch::estimateDelay(WireId src, WireId dst) const
int dx = abs(src_loc.first - dst_loc.first), dy = abs(src_loc.second - dst_loc.second); int dx = abs(src_loc.first - dst_loc.first), dy = abs(src_loc.second - dst_loc.second);
return (130 - 25 * args.speed) * 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))); (6 + std::max(dx - 5, 0) + std::max(dy - 5, 0) + 2 * (std::min(dx, 5) + std::min(dy, 5)));
} }
delay_t Arch::predictDelay(const NetInfo *net_info, const PortRef &sink) const delay_t Arch::predictDelay(const NetInfo *net_info, const PortRef &sink) const
@ -467,7 +468,6 @@ delay_t Arch::predictDelay(const NetInfo *net_info, const PortRef &sink) const
return 0; return 0;
auto driver_loc = getBelLocation(driver.cell->bel); auto driver_loc = getBelLocation(driver.cell->bel);
auto sink_loc = getBelLocation(sink.cell->bel); auto sink_loc = getBelLocation(sink.cell->bel);
// Encourage use of direct interconnect // Encourage use of direct interconnect
if (driver_loc.x == sink_loc.x && driver_loc.y == sink_loc.y) { if (driver_loc.x == sink_loc.x && driver_loc.y == sink_loc.y) {
if ((sink.port == id_A0 || sink.port == id_A1) && (driver.port == id_F1) && if ((sink.port == id_A0 || sink.port == id_A1) && (driver.port == id_F1) &&

View File

@ -26,10 +26,10 @@
#include "log.h" #include "log.h"
#include "nextpnr.h" #include "nextpnr.h"
#include "placer1.h" #include "placer1.h"
#include "placer_heap.h"
#include "router1.h" #include "router1.h"
#include "timing_opt.h" #include "timing_opt.h"
#include "util.h" #include "util.h"
NEXTPNR_NAMESPACE_BEGIN NEXTPNR_NAMESPACE_BEGIN
// ----------------------------------------------------------------------- // -----------------------------------------------------------------------
@ -671,7 +671,9 @@ bool Arch::getBudgetOverride(const NetInfo *net_info, const PortRef &sink, delay
bool Arch::place() bool Arch::place()
{ {
if (!placer1(getCtx(), Placer1Cfg(getCtx()))) // if (!placer1(getCtx(), Placer1Cfg(getCtx())))
// return false;
if (!placer_heap(getCtx()))
return false; return false;
if (bool_or_default(settings, id("opt_timing"), false)) { if (bool_or_default(settings, id("opt_timing"), false)) {
TimingOptCfg tocfg(getCtx()); TimingOptCfg tocfg(getCtx());