Merge remote-tracking branch 'origin' into facade
diff --git a/.gitmodules b/.gitmodules
index d01ee12..7d0eaf4 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,4 +1,4 @@
 [submodule "database"]
 	path = database
-	url = https://github.com/cr1901/prjtrellis-db.git 
+	url = https://github.com/cr1901/prjtrellis-db.git
 	branch = facade
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 610dd92..197c404 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -21,59 +21,6 @@
 follow the open source best practice of using the [Contributor
 Covenant](https://www.contributor-covenant.org/) for our Code of Conduct.
 
-### Sign your work
-
-To improve tracking of who did what, we follow the Linux Kernel's
-["sign your work" system](https://github.com/wking/signed-off-by).
-This is also called a
-["DCO" or "Developer's Certificate of Origin"](https://developercertificate.org/).
-
-**All** commits are required to include this sign off and we use the
-[Probot DCO App](https://github.com/probot/dco) to check pull requests for
-this.
-
-The sign-off is a simple line at the end of the explanation for the
-patch, which certifies that you wrote it or otherwise have the right to
-pass it on as a open-source patch.  The rules are pretty simple: if you
-can certify the below:
-
-        Developer's Certificate of Origin 1.1
-
-        By making a contribution to this project, I certify that:
-
-        (a) The contribution was created in whole or in part by me and I
-            have the right to submit it under the open source license
-            indicated in the file; or
-
-        (b) The contribution is based upon previous work that, to the best
-            of my knowledge, is covered under an appropriate open source
-            license and I have the right under that license to submit that
-            work with modifications, whether created in whole or in part
-            by me, under the same open source license (unless I am
-            permitted to submit under a different license), as indicated
-            in the file; or
-
-        (c) The contribution was provided directly to me by some other
-            person who certified (a), (b) or (c) and I have not modified
-            it.
-
-	(d) I understand and agree that this project and the contribution
-	    are public and that a record of the contribution (including all
-	    personal information I submit with it, including my sign-off) is
-	    maintained indefinitely and may be redistributed consistent with
-	    this project or the open source license(s) involved.
-
-then you just add a line saying
-
-	Signed-off-by: Random J Developer <random@developer.example.org>
-
-using your real name (sorry, no pseudonyms or anonymous contributions.)
-
-
-
-
-
-
 ----
 
 This file is generated from [README.md](README.md), please edit that file then
diff --git a/README.md b/README.md
index a3c7c62..cce4822 100644
--- a/README.md
+++ b/README.md
@@ -18,7 +18,7 @@
 
 Clone the Project Trellis repository and download the latest database:
 
-     git clone --recursive https://github.com/SymbiFlow/prjtrellis
+     git clone --recursive https://github.com/YosysHQ/prjtrellis
      
 Install _libtrellis_ and associated tools. You _must_ run `cmake` from the libtrellis directory.
 Out-of-tree builds are currently unsupported when coupled with `nextpnr`:
@@ -60,8 +60,8 @@
 ## For Developers
 
 Project Trellis documents the Lattice ECP5 bit-stream format and internal architecture. Current documentation is
-located in machine-readable format in [prjtrellis-db](https://github.com/SymbiFlow/prjtrellis-db)
-and is also [published online as HTML](https://symbiflow.github.io/prjtrellis-db/).
+located in machine-readable format in [prjtrellis-db](https://github.com/YosysHQ/prjtrellis-db)
+and is also [published online as HTML](https://yosyshq.github.io/prjtrellis-db/).
 
 This repository contains both tools and scripts which allow you to document the
 bit-stream format of Lattice ECP5 series FPGAs.
@@ -148,7 +148,7 @@
 ### Database
 
 Instead of downloading the
-[compiled part database](https://github.com/SymbiFlow/prjtrellis-db),
+[compiled part database](https://github.com/YosysHQ/prjtrellis-db),
 it can also be created from scratch. However, this procedure
 takes several hours, even on a decent workstation.
 First, the empty reference bitstreams and the tile layout must be created
diff --git a/libtrellis/CMakeLists.txt b/libtrellis/CMakeLists.txt
index c6ab645..a904497 100644
--- a/libtrellis/CMakeLists.txt
+++ b/libtrellis/CMakeLists.txt
@@ -29,7 +29,24 @@
         set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
     endif()
 endif()
-set(boost_libs filesystem thread program_options system)
+if (WASI)
+    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()
+set(boost_libs filesystem program_options system)
+if (USE_THREADS)
+    list(APPEND boost_libs thread)
+else()
+    add_definitions(-DNO_THREADS)
+endif()
 set(Boost_NO_BOOST_CMAKE ON)
 find_package(PythonInterp 3.5 REQUIRED)
 
@@ -180,6 +197,13 @@
 target_link_libraries(${PROGRAM_PREFIX}ecpmulti trellis ${Boost_LIBRARIES} ${CMAKE_DL_LIBS} ${link_param})
 setup_rpath(${PROGRAM_PREFIX}ecpmulti)
 
+if (WASI)
+    foreach (tool ecpbram ecppack ecpunpack ecppll ecpmulti)
+        # set(CMAKE_EXECUTABLE_SUFFIX) breaks CMake tests for some reason
+        set_property(TARGET ${PROGRAM_PREFIX}${tool} PROPERTY SUFFIX ".wasm")
+    endforeach()
+endif()
+
 if (BUILD_SHARED)
     install(TARGETS trellis ${PROGRAM_PREFIX}ecpbram ${PROGRAM_PREFIX}ecppack ${PROGRAM_PREFIX}ecppll ${PROGRAM_PREFIX}ecpunpack ${PROGRAM_PREFIX}ecpmulti ${PythonInstallTarget}
             LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/${PROGRAM_PREFIX}trellis
diff --git a/libtrellis/include/BitDatabase.hpp b/libtrellis/include/BitDatabase.hpp
index 6708ac6..26c88ca 100644
--- a/libtrellis/include/BitDatabase.hpp
+++ b/libtrellis/include/BitDatabase.hpp
@@ -7,8 +7,10 @@
 #include <cstdint>
 #include <boost/optional.hpp>
 #include <mutex>
+#ifndef NO_THREADS
 #include <boost/thread/shared_mutex.hpp>
 #include <atomic>
+#endif
 #include <set>
 #include <unordered_set>
 #include "Util.hpp"
@@ -331,8 +333,12 @@
 private:
     explicit TileBitDatabase(const string &filename);
 
+#ifdef NO_THREADS
+    bool dirty = false;
+#else
     mutable boost::shared_mutex db_mutex;
     atomic<bool> dirty{false};
+#endif
     map<string, MuxBits> muxes;
     map<string, WordSettingBits> words;
     map<string, EnumSettingBits> enums;
diff --git a/libtrellis/include/DatabasePath.hpp b/libtrellis/include/DatabasePath.hpp
index cab8a29..288f670 100644
--- a/libtrellis/include/DatabasePath.hpp
+++ b/libtrellis/include/DatabasePath.hpp
@@ -6,6 +6,15 @@
 
 #if BOOST_VERSION >= 106100
 
+#if defined(__wasm)
+
+std::string get_database_path()
+{
+    return "/share/trellis/database";
+}
+
+#else
+
 #include <boost/dll/runtime_symbol_info.hpp>
 
 std::string get_database_path()
@@ -16,6 +25,8 @@
     return database_folder;
 }
 
+#endif
+
 #else
 
 /*
diff --git a/libtrellis/src/Bels.cpp b/libtrellis/src/Bels.cpp
index 40c03e4..61b9dff 100644
--- a/libtrellis/src/Bels.cpp
+++ b/libtrellis/src/Bels.cpp
@@ -261,6 +261,7 @@
     bel.type = graph.ident("EHXPLLL");
     bel.loc.x = x;
     bel.loc.y = y;
+    bel.z = 0;
     auto add_input = [&](const std::string &pin) {
         graph.add_bel_input(bel, graph.ident(pin), x, y, graph.ident(fmt("J" << pin << "_PLL")));
     };
@@ -508,7 +509,7 @@
             add_output("DTROUT" + std::to_string(i));
     } else if (name == "USRMCLK") {
         postfix = "CCLK";
-        bel.z = 0;
+        bel.z = 1;
         add_input("PADDO");
         add_input("PADDT");
         add_output("PADDI");
diff --git a/libtrellis/src/BitDatabase.cpp b/libtrellis/src/BitDatabase.cpp
index 9cf5ad3..5a571c8 100644
--- a/libtrellis/src/BitDatabase.cpp
+++ b/libtrellis/src/BitDatabase.cpp
@@ -6,8 +6,10 @@
 
 #include <algorithm>
 #include <fstream>
+#ifndef NO_THREADS
 #include <boost/thread/shared_lock_guard.hpp>
 #include <boost/thread/lock_guard.hpp>
+#endif
 #include <boost/range/algorithm/copy.hpp>
 #include <boost/range/adaptors.hpp>
 
@@ -335,7 +337,9 @@
 
 void TileBitDatabase::config_to_tile_cram(const TileConfig &cfg, CRAMView &tile, bool is_tilegroup, set<string> *tg_matches) const
 {
+#ifndef NO_THREADS
     boost::shared_lock_guard<boost::shared_mutex> guard(db_mutex);
+#endif
     for (auto arc : cfg.carcs)
         muxes.at(arc.sink).set_driver(tile, arc.source);
     set<string> found_words, found_enums;
@@ -397,7 +401,9 @@
 
 TileConfig TileBitDatabase::tile_cram_to_config(const CRAMView &tile) const
 {
+#ifndef NO_THREADS
     boost::shared_lock_guard<boost::shared_mutex> guard(db_mutex);
+#endif
     TileConfig cfg;
     BitSet coverage;
     for (auto mux : muxes) {
@@ -431,7 +437,9 @@
 
 void TileBitDatabase::load()
 {
+#ifndef NO_THREADS
     boost::lock_guard<boost::shared_mutex> guard(db_mutex);
+#endif
     ifstream in(filename);
     if (!in) {
         throw runtime_error("failed to open tilebit database file " + filename);
@@ -466,7 +474,9 @@
 
 void TileBitDatabase::save()
 {
+#ifndef NO_THREADS
     boost::lock_guard<boost::shared_mutex> guard(db_mutex);
+#endif
     ofstream out(filename);
     if (!out) {
         throw runtime_error("failed to open tilebit database file " + filename + " for writing");
@@ -488,7 +498,9 @@
 
 vector<string> TileBitDatabase::get_sinks() const
 {
+#ifndef NO_THREADS
     boost::shared_lock_guard<boost::shared_mutex> guard(db_mutex);
+#endif
     vector<string> result;
     boost::copy(muxes | boost::adaptors::map_keys, back_inserter(result));
     return result;
@@ -496,13 +508,17 @@
 
 MuxBits TileBitDatabase::get_mux_data_for_sink(const string &sink) const
 {
+#ifndef NO_THREADS
     boost::shared_lock_guard<boost::shared_mutex> guard(db_mutex);
+#endif
     return muxes.at(sink);
 }
 
 vector<string> TileBitDatabase::get_settings_words() const
 {
+#ifndef NO_THREADS
     boost::shared_lock_guard<boost::shared_mutex> guard(db_mutex);
+#endif
     vector<string> result;
     boost::copy(words | boost::adaptors::map_keys, back_inserter(result));
     return result;
@@ -510,13 +526,17 @@
 
 WordSettingBits TileBitDatabase::get_data_for_setword(const string &name) const
 {
+#ifndef NO_THREADS
     boost::shared_lock_guard<boost::shared_mutex> guard(db_mutex);
+#endif
     return words.at(name);
 }
 
 vector<string> TileBitDatabase::get_settings_enums() const
 {
+#ifndef NO_THREADS
     boost::shared_lock_guard<boost::shared_mutex> guard(db_mutex);
+#endif
     vector<string> result;
     boost::copy(enums | boost::adaptors::map_keys, back_inserter(result));
     return result;
@@ -524,13 +544,17 @@
 
 EnumSettingBits TileBitDatabase::get_data_for_enum(const string &name) const
 {
+#ifndef NO_THREADS
     boost::shared_lock_guard<boost::shared_mutex> guard(db_mutex);
+#endif
     return enums.at(name);
 }
 
 vector<FixedConnection> TileBitDatabase::get_fixed_conns() const
 {
+#ifndef NO_THREADS
     boost::shared_lock_guard<boost::shared_mutex> guard(db_mutex);
+#endif
     vector<FixedConnection> result;
     for (const auto &csink : fixed_conns) {
         for (const auto &conn : csink.second) {
@@ -560,7 +584,9 @@
 
 void TileBitDatabase::add_routing(const TileInfo &tile, RoutingGraph &graph) const
 {
+#ifndef NO_THREADS
     boost::shared_lock_guard<boost::shared_mutex> guard(db_mutex);
+#endif
     int row, col;
     tie(row, col) = tile.get_row_col();
     Location loc(col, row);
@@ -603,7 +629,9 @@
 
 void TileBitDatabase::add_mux_arc(const ArcData &arc)
 {
+#ifndef NO_THREADS
     boost::lock_guard<boost::shared_mutex> guard(db_mutex);
+#endif
     dirty = true;
     if (muxes.find(arc.sink) == muxes.end()) {
         MuxBits mux;
@@ -630,7 +658,9 @@
 
 void TileBitDatabase::add_setting_word(const WordSettingBits &wsb)
 {
+#ifndef NO_THREADS
     boost::lock_guard<boost::shared_mutex> guard(db_mutex);
+#endif
     dirty = true;
     if (words.find(wsb.name) != words.end()) {
         WordSettingBits &curr = words.at(wsb.name);
@@ -653,7 +683,9 @@
 
 void TileBitDatabase::add_setting_enum(const EnumSettingBits &esb)
 {
+#ifndef NO_THREADS
     boost::lock_guard<boost::shared_mutex> guard(db_mutex);
+#endif
     dirty = true;
     if (enums.find(esb.name) != enums.end()) {
         EnumSettingBits &curr = enums.at(esb.name);
@@ -677,7 +709,9 @@
 
 void TileBitDatabase::add_fixed_conn(const Trellis::FixedConnection &conn)
 {
+#ifndef NO_THREADS
     boost::lock_guard<boost::shared_mutex> guard(db_mutex);
+#endif
     fixed_conns[conn.sink].insert(conn);
     dirty = true;
 }
@@ -691,19 +725,25 @@
 
 void TileBitDatabase::remove_fixed_sink(const string &sink)
 {
+#ifndef NO_THREADS
     boost::lock_guard<boost::shared_mutex> guard(db_mutex);
+#endif
     fixed_conns.erase(sink);
 }
 
 void TileBitDatabase::remove_setting_enum(const string &enum_name)
 {
+#ifndef NO_THREADS
     boost::lock_guard<boost::shared_mutex> guard(db_mutex);
+#endif
     enums.erase(enum_name);
 }
 
 void TileBitDatabase::remove_setting_word(const string &word_name)
 {
+#ifndef NO_THREADS
     boost::lock_guard<boost::shared_mutex> guard(db_mutex);
+#endif
     words.erase(word_name);
 }
 
diff --git a/libtrellis/src/Database.cpp b/libtrellis/src/Database.cpp
index e4ac515..5f70c08 100644
--- a/libtrellis/src/Database.cpp
+++ b/libtrellis/src/Database.cpp
@@ -19,7 +19,9 @@
 
 // Cache Tilegrid data, to save time parsing it again
 static map<string, pt::ptree> tilegrid_cache;
+#ifndef NO_THREADS
 static mutex tilegrid_cache_mutex;
+#endif
 
 void load_database(string root) {
     db_root = root;
@@ -201,7 +203,9 @@
     string tilegrid_path = db_root + "/" + part.family + "/" + part.device + "/tilegrid.json";
     {
         ChipInfo info = get_chip_info(part);
+#ifndef NO_THREADS
         lock_guard <mutex> lock(tilegrid_cache_mutex);
+#endif
         if (tilegrid_cache.find(part.device) == tilegrid_cache.end()) {
             pt::ptree tg_parsed;
             pt::read_json(tilegrid_path, tg_parsed);
@@ -237,10 +241,14 @@
 }
 
 static unordered_map<TileLocator, shared_ptr<TileBitDatabase>> bitdb_store;
+#ifndef NO_THREADS
 static mutex bitdb_store_mutex;
+#endif
 
 shared_ptr<TileBitDatabase> get_tile_bitdata(const TileLocator &tile) {
+#ifndef NO_THREADS
     lock_guard <mutex> bitdb_store_lg(bitdb_store_mutex);
+#endif
     if (bitdb_store.find(tile) == bitdb_store.end()) {
         assert(!db_root.empty());
         string bitdb_path = db_root + "/" + tile.family + "/tiledata/" + tile.tiletype + "/bits.db";
diff --git a/libtrellis/tools/ecpbram.cpp b/libtrellis/tools/ecpbram.cpp
index a1bc205..7e424f1 100644
--- a/libtrellis/tools/ecpbram.cpp
+++ b/libtrellis/tools/ecpbram.cpp
@@ -41,6 +41,7 @@
 #include "Chip.hpp"
 #include "Database.hpp"
 #include "DatabasePath.hpp"
+#include "wasmexcept.hpp"
 
 using std::map;
 using std::pair;
@@ -124,11 +125,6 @@
 int main(int argc, char **argv)
 {
     bool verbose = false;
-#ifdef _WIN32
-    uint32_t seed_nr = GetCurrentProcessId();
-#else
-    uint32_t seed_nr = getpid();
-#endif
     namespace po = boost::program_options;
 
     std::string database_folder = get_database_path();;
@@ -197,14 +193,26 @@
             return 1;
         }
 
+        // If -s is provided: seed with the given value.
+        // If -s is not provided: seed with the PID and current time, which are unlikely 
+        // to repeat simultaneously.
+        uint32_t seed_nr;
         if (vm.count("seed")) {
             seed_nr = vm.at("seed").as<int>();
 
             if (verbose)
                 fprintf(stderr, "Seed: %d\n", seed_nr);
+        } else {
+#if defined(__wasm)
+            seed_nr = 0;
+#elif defined(_WIN32)
+            seed_nr = GetCurrentProcessId();
+#else
+            seed_nr = getpid();
+#endif
         }
 
-        x  =  uint64_t(seed_nr) << 32;
+        x  = uint64_t(seed_nr) << 32;
         x ^= uint64_t(seed_nr) << 20;
         x ^= uint64_t(seed_nr);
 
diff --git a/libtrellis/tools/ecpmulti.cpp b/libtrellis/tools/ecpmulti.cpp
index 83232e1..20ddaec 100644
--- a/libtrellis/tools/ecpmulti.cpp
+++ b/libtrellis/tools/ecpmulti.cpp
@@ -6,6 +6,7 @@
 #include "DatabasePath.hpp"
 #include "Tile.hpp"
 #include "version.hpp"
+#include "wasmexcept.hpp"
 #include <iostream>
 #include <boost/program_options.hpp>
 #include <stdexcept>
diff --git a/libtrellis/tools/ecppack.cpp b/libtrellis/tools/ecppack.cpp
index d6aea40..6bf2895 100644
--- a/libtrellis/tools/ecppack.cpp
+++ b/libtrellis/tools/ecppack.cpp
@@ -6,7 +6,7 @@
 #include "Tile.hpp"
 #include "BitDatabase.hpp"
 #include "version.hpp"
-
+#include "wasmexcept.hpp"
 #include <iostream>
 #include <boost/program_options.hpp>
 #include <stdexcept>
diff --git a/libtrellis/tools/ecppll.cpp b/libtrellis/tools/ecppll.cpp
index 13e6b26..a3e5b3c 100644
--- a/libtrellis/tools/ecppll.cpp
+++ b/libtrellis/tools/ecppll.cpp
@@ -37,6 +37,7 @@
 #include <string>
 #include <boost/program_options.hpp>
 #include "version.hpp"
+#include "wasmexcept.hpp"
 using namespace std;
 
 enum class pll_mode{
diff --git a/libtrellis/tools/ecpunpack.cpp b/libtrellis/tools/ecpunpack.cpp
index a5752a8..1029356 100644
--- a/libtrellis/tools/ecpunpack.cpp
+++ b/libtrellis/tools/ecpunpack.cpp
@@ -4,6 +4,7 @@
 #include "Database.hpp"
 #include "DatabasePath.hpp"
 #include "version.hpp"
+#include "wasmexcept.hpp"
 #include <iostream>
 #include <boost/optional.hpp>
 #include <boost/program_options.hpp>
diff --git a/libtrellis/tools/wasmexcept.hpp b/libtrellis/tools/wasmexcept.hpp
new file mode 100644
index 0000000..657d9dc
--- /dev/null
+++ b/libtrellis/tools/wasmexcept.hpp
@@ -0,0 +1,19 @@
+#if defined(__wasm)
+
+#include <cstdint>
+#include <iostream>
+
+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) { 
+	std::cerr << "boost::exception(): " << e.what() << std::endl;
+}
+} // namespace boost
+
+#endif
diff --git a/tools/html_all.py b/tools/html_all.py
index 42edfcd..a796ee6 100755
--- a/tools/html_all.py
+++ b/tools/html_all.py
@@ -28,8 +28,8 @@
 <h1>Project Trellis HTML Documentation</h1>
 <p>Project Trellis is a project to document the ECP5 bitstream and internal architecture.</p>
 <p>This repository contains HTML documentation automatically generated from the
-<a href="https://github.com/SymbiFlow/prjtrellis">Project Trellis</a> database. The equivalent
-machine-readable data is located in <a href="https://github.com/SymbiFlow/prjtrellis-db">prjtrellis-db.<a/>
+<a href="https://github.com/YosysHQ/prjtrellis">Project Trellis</a> database. The equivalent
+machine-readable data is located in <a href="https://github.com/YosysHQ/prjtrellis-db">prjtrellis-db.<a/>
 Data generated includes tilemap data and bitstream data for many tile types. Click on any tile to see its bitstream
 documentation.
 </p>
@@ -38,7 +38,7 @@
 on the <a href="http://prjtrellis.readthedocs.io/en/latest/">Read the Docs</a> site.</p>
 
 <p>This HTML documentation was generated at ${datetime} from prjtrellis-db commit
-<a href="https://github.com/SymbiFlow/prjtrellis-db/tree/${commit}">${commit}</a>.</p>
+<a href="https://github.com/YosysHQ/prjtrellis-db/tree/${commit}">${commit}</a>.</p>
 <hr/>
 $docs_toc
 <hr/>