Merge pull request #447 from whitequark/wasi

Port nextpnr-{ice40,ecp5} to WASI
This commit is contained in:
David Shah 2020-05-24 14:23:35 +01:00 committed by GitHub
commit f44498a530
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 108 additions and 20 deletions

View File

@ -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)

View File

@ -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)

View File

@ -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); }

View File

@ -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();

View File

@ -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
NEXTPNR_NAMESPACE_END

View File

@ -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();

View File

@ -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})

View File

@ -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();