Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Port nextpnr-{ice40,ecp5} to WASI #447

Merged
merged 1 commit into from
May 24, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 26 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -84,7 +102,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})

Expand All @@ -99,7 +116,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")
Expand Down Expand Up @@ -229,6 +249,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)

Expand Down
19 changes: 19 additions & 0 deletions common/nextpnr.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
14 changes: 14 additions & 0 deletions common/nextpnr.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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
Expand All @@ -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); }
Expand Down
17 changes: 12 additions & 5 deletions common/placer_heap.cc
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@
#include <Eigen/Core>
#include <Eigen/IterativeLinearSolvers>
#include <boost/optional.hpp>
#include <boost/thread.hpp>
#include <chrono>
#include <deque>
#include <fstream>
Expand Down Expand Up @@ -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();

Expand Down Expand Up @@ -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();
Expand Down
20 changes: 17 additions & 3 deletions common/router2.cc
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
#include <deque>
#include <fstream>
#include <queue>
#include <thread>
#include "log.h"
#include "nextpnr.h"
#include "router1.h"
Expand Down Expand Up @@ -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)); });
}
Expand All @@ -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)
Expand Down Expand Up @@ -1130,4 +1144,4 @@ Router2Cfg::Router2Cfg(Context *ctx)
perf_profile = ctx->setting<float>("router2/perfProfile", false);
}

NEXTPNR_NAMESPACE_END
NEXTPNR_NAMESPACE_END
5 changes: 3 additions & 2 deletions ecp5/arch.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
21 changes: 15 additions & 6 deletions ecp5/family.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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})
Expand Down
4 changes: 2 additions & 2 deletions ice40/arch.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down