Merge pull request #447 from whitequark/wasi
Port nextpnr-{ice40,ecp5} to WASI
This commit is contained in:
commit
f44498a530
@ -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)
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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); }
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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})
|
||||
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user