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)
|
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 "")
|
set(link_param "")
|
||||||
if (STATIC_BUILD)
|
if (STATIC_BUILD)
|
||||||
set(Boost_USE_STATIC_LIBS ON)
|
set(Boost_USE_STATIC_LIBS ON)
|
||||||
@ -86,7 +104,6 @@ else()
|
|||||||
set(CMAKE_CXX_FLAGS_RELEASE "-Wall -fPIC -O3 -g -pipe")
|
set(CMAKE_CXX_FLAGS_RELEASE "-Wall -fPIC -O3 -g -pipe")
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
set(CMAKE_DEFIN)
|
|
||||||
|
|
||||||
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/3rdparty/sanitizers-cmake/cmake;." ${CMAKE_MODULE_PATH})
|
set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/3rdparty/sanitizers-cmake/cmake;." ${CMAKE_MODULE_PATH})
|
||||||
|
|
||||||
@ -101,7 +118,10 @@ endif()
|
|||||||
find_package(Sanitizers)
|
find_package(Sanitizers)
|
||||||
|
|
||||||
# List of Boost libraries to include
|
# 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)
|
if (BUILD_GUI AND NOT BUILD_PYTHON)
|
||||||
message(FATAL_ERROR "GUI requires Python to build")
|
message(FATAL_ERROR "GUI requires Python to build")
|
||||||
@ -231,6 +251,10 @@ foreach (family ${ARCH})
|
|||||||
|
|
||||||
# Add the CLI binary target
|
# Add the CLI binary target
|
||||||
add_executable(${PROGRAM_PREFIX}nextpnr-${family} ${COMMON_FILES} ${${ufamily}_FILES})
|
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)
|
install(TARGETS ${PROGRAM_PREFIX}nextpnr-${family} RUNTIME DESTINATION bin)
|
||||||
target_compile_definitions(${PROGRAM_PREFIX}nextpnr-${family} PRIVATE MAIN_EXECUTABLE)
|
target_compile_definitions(${PROGRAM_PREFIX}nextpnr-${family} PRIVATE MAIN_EXECUTABLE)
|
||||||
|
|
||||||
|
@ -23,6 +23,25 @@
|
|||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "util.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
|
NEXTPNR_NAMESPACE_BEGIN
|
||||||
|
|
||||||
assertion_failure::assertion_failure(std::string msg, std::string expr_str, std::string filename, int line)
|
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/functional/hash.hpp>
|
||||||
#include <boost/lexical_cast.hpp>
|
#include <boost/lexical_cast.hpp>
|
||||||
#include <boost/range/adaptor/reversed.hpp>
|
#include <boost/range/adaptor/reversed.hpp>
|
||||||
|
#ifndef NPNR_DISABLE_THREADS
|
||||||
#include <boost/thread.hpp>
|
#include <boost/thread.hpp>
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef NEXTPNR_H
|
#ifndef NEXTPNR_H
|
||||||
#define NEXTPNR_H
|
#define NEXTPNR_H
|
||||||
@ -647,6 +649,7 @@ struct DeterministicRNG
|
|||||||
|
|
||||||
struct BaseCtx
|
struct BaseCtx
|
||||||
{
|
{
|
||||||
|
#ifndef NPNR_DISABLE_THREADS
|
||||||
// Lock to perform mutating actions on the Context.
|
// Lock to perform mutating actions on the Context.
|
||||||
std::mutex mutex;
|
std::mutex mutex;
|
||||||
boost::thread::id mutex_owner;
|
boost::thread::id mutex_owner;
|
||||||
@ -655,6 +658,7 @@ struct BaseCtx
|
|||||||
// method will lock/unlock it when its' released the main mutex to make
|
// method will lock/unlock it when its' released the main mutex to make
|
||||||
// sure the UI is not starved.
|
// sure the UI is not starved.
|
||||||
std::mutex ui_mutex;
|
std::mutex ui_mutex;
|
||||||
|
#endif
|
||||||
|
|
||||||
// ID String database.
|
// ID String database.
|
||||||
mutable std::unordered_map<std::string, int> *idstring_str_to_idx;
|
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.
|
// Must be called before performing any mutating changes on the Ctx/Arch.
|
||||||
void lock(void)
|
void lock(void)
|
||||||
{
|
{
|
||||||
|
#ifndef NPNR_DISABLE_THREADS
|
||||||
mutex.lock();
|
mutex.lock();
|
||||||
mutex_owner = boost::this_thread::get_id();
|
mutex_owner = boost::this_thread::get_id();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void unlock(void)
|
void unlock(void)
|
||||||
{
|
{
|
||||||
|
#ifndef NPNR_DISABLE_THREADS
|
||||||
NPNR_ASSERT(boost::this_thread::get_id() == mutex_owner);
|
NPNR_ASSERT(boost::this_thread::get_id() == mutex_owner);
|
||||||
mutex.unlock();
|
mutex.unlock();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Must be called by the UI before rendering data. This lock will be
|
// Must be called by the UI before rendering data. This lock will be
|
||||||
// prioritized when processing code calls yield().
|
// prioritized when processing code calls yield().
|
||||||
void lock_ui(void)
|
void lock_ui(void)
|
||||||
{
|
{
|
||||||
|
#ifndef NPNR_DISABLE_THREADS
|
||||||
ui_mutex.lock();
|
ui_mutex.lock();
|
||||||
mutex.lock();
|
mutex.lock();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void unlock_ui(void)
|
void unlock_ui(void)
|
||||||
{
|
{
|
||||||
|
#ifndef NPNR_DISABLE_THREADS
|
||||||
mutex.unlock();
|
mutex.unlock();
|
||||||
ui_mutex.unlock();
|
ui_mutex.unlock();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Yield to UI by unlocking the main mutex, flashing the UI mutex and
|
// 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.
|
// Must be called with the main lock taken.
|
||||||
void yield(void)
|
void yield(void)
|
||||||
{
|
{
|
||||||
|
#ifndef NPNR_DISABLE_THREADS
|
||||||
unlock();
|
unlock();
|
||||||
ui_mutex.lock();
|
ui_mutex.lock();
|
||||||
ui_mutex.unlock();
|
ui_mutex.unlock();
|
||||||
lock();
|
lock();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
IdString id(const std::string &s) const { return IdString(this, s); }
|
IdString id(const std::string &s) const { return IdString(this, s); }
|
||||||
|
@ -37,7 +37,6 @@
|
|||||||
#include <Eigen/Core>
|
#include <Eigen/Core>
|
||||||
#include <Eigen/IterativeLinearSolvers>
|
#include <Eigen/IterativeLinearSolvers>
|
||||||
#include <boost/optional.hpp>
|
#include <boost/optional.hpp>
|
||||||
#include <boost/thread.hpp>
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
@ -154,9 +153,14 @@ class HeAPPlacer
|
|||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
setup_solve_cells();
|
setup_solve_cells();
|
||||||
auto solve_startt = std::chrono::high_resolution_clock::now();
|
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); });
|
boost::thread xaxis([&]() { build_solve_direction(false, -1); });
|
||||||
build_solve_direction(true, -1);
|
build_solve_direction(true, -1);
|
||||||
xaxis.join();
|
xaxis.join();
|
||||||
|
#endif
|
||||||
auto solve_endt = std::chrono::high_resolution_clock::now();
|
auto solve_endt = std::chrono::high_resolution_clock::now();
|
||||||
solve_time += std::chrono::duration<double>(solve_endt - solve_startt).count();
|
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
|
// Heuristic: don't bother with threading below a certain size
|
||||||
auto solve_startt = std::chrono::high_resolution_clock::now();
|
auto solve_startt = std::chrono::high_resolution_clock::now();
|
||||||
|
|
||||||
if (solve_cells.size() < 500) {
|
#ifndef NPNR_DISABLE_THREADS
|
||||||
build_solve_direction(false, (iter == 0) ? -1 : iter);
|
if (solve_cells.size() >= 500) {
|
||||||
build_solve_direction(true, (iter == 0) ? -1 : iter);
|
|
||||||
} else {
|
|
||||||
boost::thread xaxis([&]() { build_solve_direction(false, (iter == 0) ? -1 : iter); });
|
boost::thread xaxis([&]() { build_solve_direction(false, (iter == 0) ? -1 : iter); });
|
||||||
build_solve_direction(true, (iter == 0) ? -1 : iter);
|
build_solve_direction(true, (iter == 0) ? -1 : iter);
|
||||||
xaxis.join();
|
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();
|
auto solve_endt = std::chrono::high_resolution_clock::now();
|
||||||
solve_time += std::chrono::duration<double>(solve_endt - solve_startt).count();
|
solve_time += std::chrono::duration<double>(solve_endt - solve_startt).count();
|
||||||
|
@ -33,7 +33,6 @@
|
|||||||
#include <deque>
|
#include <deque>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
#include <thread>
|
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "nextpnr.h"
|
#include "nextpnr.h"
|
||||||
#include "router1.h"
|
#include "router1.h"
|
||||||
@ -985,8 +984,22 @@ struct Router2
|
|||||||
}
|
}
|
||||||
if (ctx->verbose)
|
if (ctx->verbose)
|
||||||
log_info("%d/%d nets not multi-threadable\n", int(tcs.at(N).route_nets.size()), int(route_queue.size()));
|
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
|
// Multithreaded part of routing - quadrants
|
||||||
std::vector<std::thread> threads;
|
std::vector<boost::thread> threads;
|
||||||
for (int i = 0; i < Nq; i++) {
|
for (int i = 0; i < Nq; i++) {
|
||||||
threads.emplace_back([this, &tcs, i]() { router_thread(tcs.at(i)); });
|
threads.emplace_back([this, &tcs, i]() { router_thread(tcs.at(i)); });
|
||||||
}
|
}
|
||||||
@ -1007,6 +1020,7 @@ struct Router2
|
|||||||
for (auto &t : threads)
|
for (auto &t : threads)
|
||||||
t.join();
|
t.join();
|
||||||
threads.clear();
|
threads.clear();
|
||||||
|
#endif
|
||||||
// Singlethreaded part of routing - nets that cross partitions
|
// Singlethreaded part of routing - nets that cross partitions
|
||||||
// or don't fit within bounding box
|
// or don't fit within bounding box
|
||||||
for (auto st_net : tcs.at(N).route_nets)
|
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);
|
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_45k = nullptr;
|
||||||
const char *chipdb_blob_85k = 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)
|
const char *mmap_file(int index, const char *filename)
|
||||||
{
|
{
|
||||||
try {
|
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())
|
if (!blob_files[index].is_open())
|
||||||
log_error("Unable to read chipdb %s\n", filename);
|
log_error("Unable to read chipdb %s\n", filename);
|
||||||
return (const char *)blob_files[index].data();
|
return (const char *)blob_files[index].data();
|
||||||
|
@ -70,8 +70,9 @@ if (NOT EXTERNAL_CHIPDB)
|
|||||||
target_compile_options(ecp5_chipdb PRIVATE -g0 -O0 -w)
|
target_compile_options(ecp5_chipdb PRIVATE -g0 -O0 -w)
|
||||||
set(PREV_DEV_CC_BBA_DB)
|
set(PREV_DEV_CC_BBA_DB)
|
||||||
foreach (dev ${devices})
|
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_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_CONSTIDS_INC ${CMAKE_CURRENT_SOURCE_DIR}/ecp5/constids.inc)
|
||||||
set(DEV_GFXH ${CMAKE_CURRENT_SOURCE_DIR}/ecp5/gfx.h)
|
set(DEV_GFXH ${CMAKE_CURRENT_SOURCE_DIR}/ecp5/gfx.h)
|
||||||
if (PREGENERATED_BBA_PATH)
|
if (PREGENERATED_BBA_PATH)
|
||||||
@ -85,11 +86,19 @@ if (NOT EXTERNAL_CHIPDB)
|
|||||||
COMMAND mv ${DEV_CC_BBA_DB}.new ${DEV_CC_BBA_DB}
|
COMMAND mv ${DEV_CC_BBA_DB}.new ${DEV_CC_BBA_DB}
|
||||||
DEPENDS ${DB_PY} ${DEV_CONSTIDS_INC} ${DEV_GFXH} ${PREV_DEV_CC_BBA_DB}
|
DEPENDS ${DB_PY} ${DEV_CONSTIDS_INC} ${DEV_GFXH} ${PREV_DEV_CC_BBA_DB}
|
||||||
)
|
)
|
||||||
add_custom_command(OUTPUT ${DEV_CC_DB}
|
if(USE_C_EMBED)
|
||||||
COMMAND bbasm --c ${BBASM_ENDIAN_FLAG} ${DEV_CC_BBA_DB} ${DEV_CC_DB}.new
|
add_custom_command(OUTPUT ${DEV_CC_DB}
|
||||||
COMMAND mv ${DEV_CC_DB}.new ${DEV_CC_DB}
|
COMMAND bbasm --e ${BBASM_ENDIAN_FLAG} ${DEV_CC_BBA_DB} ${DEV_CC_DB}.new ${DEV_BIN_DB}
|
||||||
DEPENDS bbasm ${DEV_CC_BBA_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()
|
endif()
|
||||||
if (SERIALIZE_CHIPDB)
|
if (SERIALIZE_CHIPDB)
|
||||||
set(PREV_DEV_CC_BBA_DB ${DEV_CC_BBA_DB})
|
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_u4k = nullptr;
|
||||||
const char *chipdb_blob_8k = 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)
|
const char *mmap_file(int index, const char *filename)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
blob_files[index].open(filename);
|
blob_files[index].open(filename, boost::iostreams::mapped_file::priv);
|
||||||
if (!blob_files[index].is_open())
|
if (!blob_files[index].is_open())
|
||||||
log_error("Unable to read chipdb %s\n", filename);
|
log_error("Unable to read chipdb %s\n", filename);
|
||||||
return (const char *)blob_files[index].data();
|
return (const char *)blob_files[index].data();
|
||||||
|
Loading…
Reference in New Issue
Block a user