aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Shah <dave@ds0.me>2020-05-24 14:23:35 +0100
committerGitHub <noreply@github.com>2020-05-24 14:23:35 +0100
commitf44498a5301f9f516488fb748c684926be514346 (patch)
treed37948e9ad90850c2d90566cebc5dc6d4ac07fb9
parent2d406f3e275beda8b70b4c7d4d5e43433dd3c43c (diff)
parente7bb04769d5d7262d3ecfd0de49953078174a880 (diff)
downloadnextpnr-f44498a5301f9f516488fb748c684926be514346.tar.gz
nextpnr-f44498a5301f9f516488fb748c684926be514346.tar.bz2
nextpnr-f44498a5301f9f516488fb748c684926be514346.zip
Merge pull request #447 from whitequark/wasi
Port nextpnr-{ice40,ecp5} to WASI
-rw-r--r--CMakeLists.txt28
-rw-r--r--common/nextpnr.cc19
-rw-r--r--common/nextpnr.h14
-rw-r--r--common/placer_heap.cc17
-rw-r--r--common/router2.cc20
-rw-r--r--ecp5/arch.cc5
-rw-r--r--ecp5/family.cmake21
-rw-r--r--ice40/arch.cc4
8 files changed, 108 insertions, 20 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9bd85194..21133e3d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -14,6 +14,24 @@ option(SERIALIZE_CHIPDB "Never build chipdb in parallel to reduce peak memory us
set(Boost_NO_BOOST_CMAKE ON)
+if(WASI)
+ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lwasi-emulated-mman")
+ set(USE_THREADS OFF)
+ add_definitions(
+ -DBOOST_EXCEPTION_DISABLE
+ -DBOOST_NO_EXCEPTIONS
+ -DBOOST_SP_NO_ATOMIC_ACCESS
+ -DBOOST_AC_DISABLE_THREADS
+ -DBOOST_NO_CXX11_HDR_MUTEX
+ )
+else()
+ set(USE_THREADS ON)
+endif()
+
+if (NOT USE_THREADS)
+ add_definitions(-DNPNR_DISABLE_THREADS)
+endif()
+
set(link_param "")
if (STATIC_BUILD)
set(Boost_USE_STATIC_LIBS ON)
@@ -86,7 +104,6 @@ else()
set(CMAKE_CXX_FLAGS_RELEASE "-Wall -fPIC -O3 -g -pipe")
endif()
endif()
-set(CMAKE_DEFIN)
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/3rdparty/sanitizers-cmake/cmake;." ${CMAKE_MODULE_PATH})
@@ -101,7 +118,10 @@ endif()
find_package(Sanitizers)
# List of Boost libraries to include
-set(boost_libs filesystem thread program_options iostreams system)
+set(boost_libs filesystem program_options iostreams system)
+if (USE_THREADS)
+ list(APPEND boost_libs thread)
+endif()
if (BUILD_GUI AND NOT BUILD_PYTHON)
message(FATAL_ERROR "GUI requires Python to build")
@@ -231,6 +251,10 @@ foreach (family ${ARCH})
# Add the CLI binary target
add_executable(${PROGRAM_PREFIX}nextpnr-${family} ${COMMON_FILES} ${${ufamily}_FILES})
+ if (WASI)
+ # set(CMAKE_EXECUTABLE_SUFFIX) breaks CMake tests for some reason
+ set_property(TARGET ${PROGRAM_PREFIX}nextpnr-${family} PROPERTY SUFFIX ".wasm")
+ endif()
install(TARGETS ${PROGRAM_PREFIX}nextpnr-${family} RUNTIME DESTINATION bin)
target_compile_definitions(${PROGRAM_PREFIX}nextpnr-${family} PRIVATE MAIN_EXECUTABLE)
diff --git a/common/nextpnr.cc b/common/nextpnr.cc
index 1156490c..c16a601c 100644
--- a/common/nextpnr.cc
+++ b/common/nextpnr.cc
@@ -23,6 +23,25 @@
#include "log.h"
#include "util.h"
+#if defined(__wasm)
+extern "C" {
+ // FIXME: WASI does not currently support exceptions.
+ void* __cxa_allocate_exception(size_t thrown_size) throw() {
+ return malloc(thrown_size);
+ }
+ bool __cxa_uncaught_exception() throw();
+ void __cxa_throw(void* thrown_exception, struct std::type_info * tinfo, void (*dest)(void*)) {
+ std::terminate();
+ }
+}
+
+namespace boost {
+ void throw_exception( std::exception const & e ) {
+ NEXTPNR_NAMESPACE::log_error("boost::exception(): %s\n", e.what());
+ }
+}
+#endif
+
NEXTPNR_NAMESPACE_BEGIN
assertion_failure::assertion_failure(std::string msg, std::string expr_str, std::string filename, int line)
diff --git a/common/nextpnr.h b/common/nextpnr.h
index 66bba997..4d481d06 100644
--- a/common/nextpnr.h
+++ b/common/nextpnr.h
@@ -33,7 +33,9 @@
#include <boost/functional/hash.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/range/adaptor/reversed.hpp>
+#ifndef NPNR_DISABLE_THREADS
#include <boost/thread.hpp>
+#endif
#ifndef NEXTPNR_H
#define NEXTPNR_H
@@ -647,6 +649,7 @@ struct DeterministicRNG
struct BaseCtx
{
+#ifndef NPNR_DISABLE_THREADS
// Lock to perform mutating actions on the Context.
std::mutex mutex;
boost::thread::id mutex_owner;
@@ -655,6 +658,7 @@ struct BaseCtx
// method will lock/unlock it when its' released the main mutex to make
// sure the UI is not starved.
std::mutex ui_mutex;
+#endif
// ID String database.
mutable std::unordered_map<std::string, int> *idstring_str_to_idx;
@@ -706,28 +710,36 @@ struct BaseCtx
// Must be called before performing any mutating changes on the Ctx/Arch.
void lock(void)
{
+#ifndef NPNR_DISABLE_THREADS
mutex.lock();
mutex_owner = boost::this_thread::get_id();
+#endif
}
void unlock(void)
{
+#ifndef NPNR_DISABLE_THREADS
NPNR_ASSERT(boost::this_thread::get_id() == mutex_owner);
mutex.unlock();
+#endif
}
// Must be called by the UI before rendering data. This lock will be
// prioritized when processing code calls yield().
void lock_ui(void)
{
+#ifndef NPNR_DISABLE_THREADS
ui_mutex.lock();
mutex.lock();
+#endif
}
void unlock_ui(void)
{
+#ifndef NPNR_DISABLE_THREADS
mutex.unlock();
ui_mutex.unlock();
+#endif
}
// Yield to UI by unlocking the main mutex, flashing the UI mutex and
@@ -737,10 +749,12 @@ struct BaseCtx
// Must be called with the main lock taken.
void yield(void)
{
+#ifndef NPNR_DISABLE_THREADS
unlock();
ui_mutex.lock();
ui_mutex.unlock();
lock();
+#endif
}
IdString id(const std::string &s) const { return IdString(this, s); }
diff --git a/common/placer_heap.cc b/common/placer_heap.cc
index c04e7091..8c43c433 100644
--- a/common/placer_heap.cc
+++ b/common/placer_heap.cc
@@ -37,7 +37,6 @@
#include <Eigen/Core>
#include <Eigen/IterativeLinearSolvers>
#include <boost/optional.hpp>
-#include <boost/thread.hpp>
#include <chrono>
#include <deque>
#include <fstream>
@@ -154,9 +153,14 @@ class HeAPPlacer
for (int i = 0; i < 4; i++) {
setup_solve_cells();
auto solve_startt = std::chrono::high_resolution_clock::now();
+#ifdef NPNR_DISABLE_THREADS
+ build_solve_direction(false, -1);
+ build_solve_direction(true, -1);
+#else
boost::thread xaxis([&]() { build_solve_direction(false, -1); });
build_solve_direction(true, -1);
xaxis.join();
+#endif
auto solve_endt = std::chrono::high_resolution_clock::now();
solve_time += std::chrono::duration<double>(solve_endt - solve_startt).count();
@@ -211,13 +215,16 @@ class HeAPPlacer
// Heuristic: don't bother with threading below a certain size
auto solve_startt = std::chrono::high_resolution_clock::now();
- if (solve_cells.size() < 500) {
- build_solve_direction(false, (iter == 0) ? -1 : iter);
- build_solve_direction(true, (iter == 0) ? -1 : iter);
- } else {
+#ifndef NPNR_DISABLE_THREADS
+ if (solve_cells.size() >= 500) {
boost::thread xaxis([&]() { build_solve_direction(false, (iter == 0) ? -1 : iter); });
build_solve_direction(true, (iter == 0) ? -1 : iter);
xaxis.join();
+ } else
+#endif
+ {
+ build_solve_direction(false, (iter == 0) ? -1 : iter);
+ build_solve_direction(true, (iter == 0) ? -1 : iter);
}
auto solve_endt = std::chrono::high_resolution_clock::now();
solve_time += std::chrono::duration<double>(solve_endt - solve_startt).count();
diff --git a/common/router2.cc b/common/router2.cc
index 26e78eaa..4dfd868b 100644
--- a/common/router2.cc
+++ b/common/router2.cc
@@ -33,7 +33,6 @@
#include <deque>
#include <fstream>
#include <queue>
-#include <thread>
#include "log.h"
#include "nextpnr.h"
#include "router1.h"
@@ -985,8 +984,22 @@ struct Router2
}
if (ctx->verbose)
log_info("%d/%d nets not multi-threadable\n", int(tcs.at(N).route_nets.size()), int(route_queue.size()));
+#ifdef NPNR_DISABLE_THREADS
+ // Singlethreaded routing - quadrants
+ for (int i = 0; i < Nq; i++) {
+ router_thread(tcs.at(i));
+ }
+ // Vertical splits
+ for (int i = Nq; i < Nq + Nv; i++) {
+ router_thread(tcs.at(i));
+ }
+ // Horizontal splits
+ for (int i = Nq + Nv; i < Nq + Nv + Nh; i++) {
+ router_thread(tcs.at(i));
+ }
+#else
// Multithreaded part of routing - quadrants
- std::vector<std::thread> threads;
+ std::vector<boost::thread> threads;
for (int i = 0; i < Nq; i++) {
threads.emplace_back([this, &tcs, i]() { router_thread(tcs.at(i)); });
}
@@ -1007,6 +1020,7 @@ struct Router2
for (auto &t : threads)
t.join();
threads.clear();
+#endif
// Singlethreaded part of routing - nets that cross partitions
// or don't fit within bounding box
for (auto st_net : tcs.at(N).route_nets)
@@ -1130,4 +1144,4 @@ Router2Cfg::Router2Cfg(Context *ctx)
perf_profile = ctx->setting<float>("router2/perfProfile", false);
}
-NEXTPNR_NAMESPACE_END \ No newline at end of file
+NEXTPNR_NAMESPACE_END
diff --git a/ecp5/arch.cc b/ecp5/arch.cc
index db043f35..3c00099f 100644
--- a/ecp5/arch.cc
+++ b/ecp5/arch.cc
@@ -71,12 +71,13 @@ const char *chipdb_blob_25k = nullptr;
const char *chipdb_blob_45k = nullptr;
const char *chipdb_blob_85k = nullptr;
-boost::iostreams::mapped_file_source blob_files[3];
+boost::iostreams::mapped_file blob_files[3];
const char *mmap_file(int index, const char *filename)
{
try {
- blob_files[index].open(filename);
+ // WASI only supports MAP_PRIVATE
+ blob_files[index].open(filename, boost::iostreams::mapped_file::priv);
if (!blob_files[index].is_open())
log_error("Unable to read chipdb %s\n", filename);
return (const char *)blob_files[index].data();
diff --git a/ecp5/family.cmake b/ecp5/family.cmake
index 9415e37e..247a307a 100644
--- a/ecp5/family.cmake
+++ b/ecp5/family.cmake
@@ -70,8 +70,9 @@ if (NOT EXTERNAL_CHIPDB)
target_compile_options(ecp5_chipdb PRIVATE -g0 -O0 -w)
set(PREV_DEV_CC_BBA_DB)
foreach (dev ${devices})
- set(DEV_CC_DB ${CMAKE_CURRENT_BINARY_DIR}/ecp5/chipdbs/chipdb-${dev}.cc)
set(DEV_CC_BBA_DB ${CMAKE_CURRENT_BINARY_DIR}/ecp5/chipdbs/chipdb-${dev}.bba)
+ set(DEV_CC_DB ${CMAKE_CURRENT_BINARY_DIR}/ecp5/chipdbs/chipdb-${dev}.cc)
+ set(DEV_BIN_DB ${CMAKE_CURRENT_BINARY_DIR}/ecp5/chipdbs/chipdb-${dev}.bin)
set(DEV_CONSTIDS_INC ${CMAKE_CURRENT_SOURCE_DIR}/ecp5/constids.inc)
set(DEV_GFXH ${CMAKE_CURRENT_SOURCE_DIR}/ecp5/gfx.h)
if (PREGENERATED_BBA_PATH)
@@ -85,11 +86,19 @@ if (NOT EXTERNAL_CHIPDB)
COMMAND mv ${DEV_CC_BBA_DB}.new ${DEV_CC_BBA_DB}
DEPENDS ${DB_PY} ${DEV_CONSTIDS_INC} ${DEV_GFXH} ${PREV_DEV_CC_BBA_DB}
)
- add_custom_command(OUTPUT ${DEV_CC_DB}
- COMMAND bbasm --c ${BBASM_ENDIAN_FLAG} ${DEV_CC_BBA_DB} ${DEV_CC_DB}.new
- COMMAND mv ${DEV_CC_DB}.new ${DEV_CC_DB}
- DEPENDS bbasm ${DEV_CC_BBA_DB}
- )
+ if(USE_C_EMBED)
+ add_custom_command(OUTPUT ${DEV_CC_DB}
+ COMMAND bbasm --e ${BBASM_ENDIAN_FLAG} ${DEV_CC_BBA_DB} ${DEV_CC_DB}.new ${DEV_BIN_DB}
+ COMMAND mv ${DEV_CC_DB}.new ${DEV_CC_DB}
+ DEPENDS bbasm ${DEV_CC_BBA_DB}
+ )
+ else()
+ add_custom_command(OUTPUT ${DEV_CC_DB}
+ COMMAND bbasm --c ${BBASM_ENDIAN_FLAG} ${DEV_CC_BBA_DB} ${DEV_CC_DB}.new
+ COMMAND mv ${DEV_CC_DB}.new ${DEV_CC_DB}
+ DEPENDS bbasm ${DEV_CC_BBA_DB}
+ )
+ endif()
endif()
if (SERIALIZE_CHIPDB)
set(PREV_DEV_CC_BBA_DB ${DEV_CC_BBA_DB})
diff --git a/ice40/arch.cc b/ice40/arch.cc
index 6d07a949..645e93cb 100644
--- a/ice40/arch.cc
+++ b/ice40/arch.cc
@@ -57,12 +57,12 @@ const char *chipdb_blob_5k = nullptr;
const char *chipdb_blob_u4k = nullptr;
const char *chipdb_blob_8k = nullptr;
-boost::iostreams::mapped_file_source blob_files[5];
+boost::iostreams::mapped_file blob_files[5];
const char *mmap_file(int index, const char *filename)
{
try {
- blob_files[index].open(filename);
+ blob_files[index].open(filename, boost::iostreams::mapped_file::priv);
if (!blob_files[index].is_open())
log_error("Unable to read chipdb %s\n", filename);
return (const char *)blob_files[index].data();