Merge remote-tracking branch 'origin/master' into facade
diff --git a/.github/archlinux/PKGBUILD b/.github/archlinux/PKGBUILD
new file mode 100644
index 0000000..d55c6f0
--- /dev/null
+++ b/.github/archlinux/PKGBUILD
@@ -0,0 +1,61 @@
+# Maintainer: Filipe Laíns (FFY00) <lains@archlinux.org>
+
+_prj=trellis
+_pkgname=prj$_prj
+pkgname=$_pkgname-git
+_commit=%COMMIT%
+pkgver=dummy
+pkgrel=1
+pkgdesc='Documentation and definitions for the Lattice ECP5 bit-stream format'
+arch=('x86_64')
+url='https://github.com/SymbiFlow/prjtrellis'
+license=('custom:ISC' 'MIT')
+depends=('boost-libs' "$_pkgname-db")
+makedepends=('git' 'cmake' 'boost' 'python-sphinx' 'python-sphinx_rtd_theme' 'python-recommonmark')
+optdepends=('python: Python support')
+provides=("$_pkgname")
+conflicts=("$_pkgname")
+source=("git+$url.git#commit=$_commit")
+sha512sums=('SKIP')
+
+pkgver() {
+  cd $_pkgname
+
+  printf "%s.r%s.%s" \
+        $(git tag | tail -n1) \
+        $(git rev-list --count HEAD) \
+        $(git rev-parse --short HEAD)
+}
+
+build() {
+  mkdir $_pkgname/libtrellis/build
+  cd $_pkgname/libtrellis/build
+
+  cmake .. \
+    -DCMAKE_INSTALL_PREFIX=/usr \
+    -DCMAKE_INSTALL_LIBDIR=/usr/lib \
+    -DCMAKE_BUILD_TYPE=Release
+
+  make
+
+#  cd ../../docs
+#
+#  make html
+}
+
+package() {
+  cd $_pkgname
+
+#  install -dm 755 "$pkgdir"/usr/share/doc/$pkgname
+#  cp -r --no-preserve=ownership docs/_build/* "$pkgdir"/usr/share/doc/$pkgname/
+
+  install -Dm 644 COPYING "$pkgdir"/usr/share/licenses/$pkgname/LICENSE
+
+  cd libtrellis/build
+
+  make DESTDIR="$pkgdir" install
+
+  # The database is provided in a separate package
+  rmdir "$pkgdir"/usr/share/$_prj/database
+}
+
diff --git a/.github/workflows/arch-pkg.yml b/.github/workflows/arch-pkg.yml
new file mode 100644
index 0000000..5b24d8b
--- /dev/null
+++ b/.github/workflows/arch-pkg.yml
@@ -0,0 +1,19 @@
+name: arch-pkg
+on: [push, pull_request]
+
+jobs:
+  arch-pkg:
+    runs-on: ubuntu-latest
+    container:
+      image: archlinux
+      options: --privileged
+      volumes:
+        - /sys/fs/cgroup:/sys/fs/cgroup
+    steps:
+      - uses: actions/checkout@v2
+      - name: Build Arch Linux package
+        uses: FFY00/build-arch-package@master
+        with:
+          PKGBUILD: $GITHUB_WORKSPACE/.github/archlinux/PKGBUILD
+
+
diff --git a/database b/database
index e9b5acf..13da868 160000
--- a/database
+++ b/database
@@ -1 +1 @@
-Subproject commit e9b5acfd93be17beed595b1ddfa689ccdf4f91a2
+Subproject commit 13da86838ba39f882a81a9fabe030b4c653854c9
diff --git a/devices.json b/devices.json
index 4d79d6e..68df05f 100644
--- a/devices.json
+++ b/devices.json
@@ -2,6 +2,18 @@
   "families": {
     "ECP5": {
       "devices": {
+            "LFE5U-12F": {
+                "packages": ["csfBGA285", "caBGA256", "caBGA381", "caBGA554", "caBGA756"],
+                "idcode": "0x21111043",
+                "frames": 7562,
+                "bits_per_frame": 592,
+                "pad_bits_after_frame": 0,
+                "pad_bits_before_frame": 0,
+                "max_row" : 50,
+                "max_col" : 72,
+                "col_bias" : 0,
+                "fuzz": 1
+            },
             "LFE5U-25F": {
                 "packages": ["csfBGA285", "caBGA256", "caBGA381", "caBGA554", "caBGA756"],
                 "idcode": "0x41111043",
diff --git a/libtrellis/CMakeLists.txt b/libtrellis/CMakeLists.txt
index 10fd498..c519daf 100644
--- a/libtrellis/CMakeLists.txt
+++ b/libtrellis/CMakeLists.txt
@@ -5,6 +5,8 @@
 option(BUILD_SHARED "Build shared Trellis library" ON)
 option(STATIC_BUILD "Create static build of Trellis tools" OFF)
 
+set(PROGRAM_PREFIX "" CACHE STRING "Name prefix for executables")
+
 set(CMAKE_CXX_STANDARD 14)
 if (MSVC)
     set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -bigobj -EHsc")
@@ -116,12 +118,12 @@
     if(APPLE)
         set_target_properties(${name} PROPERTIES
                               BUILD_WITH_INSTALL_RPATH ON
-                              INSTALL_RPATH "@loader_path/${TRELLIS_RPATH_LIBDIR}/trellis"
+                              INSTALL_RPATH "@loader_path/${TRELLIS_RPATH_LIBDIR}/${PROGRAM_PREFIX}trellis"
                               INSTALL_NAME_DIR "@rpath")
     elseif(UNIX)
         set_target_properties(${name} PROPERTIES
                               BUILD_WITH_INSTALL_RPATH ON
-                              INSTALL_RPATH "\$ORIGIN/${TRELLIS_RPATH_LIBDIR}/trellis")
+                              INSTALL_RPATH "\$ORIGIN/${TRELLIS_RPATH_LIBDIR}/${PROGRAM_PREFIX}trellis")
     endif()
 endfunction()
 
@@ -144,45 +146,45 @@
 endif()
 file(WRITE "${CMAKE_BINARY_DIR}/generated/last_git_version" CURRENT_GIT_VERSION)
 
-add_executable(ecpbram ${INCLUDE_FILES} tools/ecpbram.cpp "${CMAKE_BINARY_DIR}/generated/version.cpp")
-target_include_directories(ecpbram PRIVATE tools)
-target_compile_definitions(ecpbram PRIVATE TRELLIS_RPATH_DATADIR="${TRELLIS_RPATH_DATADIR}" TRELLIS_PREFIX="${CMAKE_INSTALL_PREFIX}")
-target_link_libraries(ecpbram trellis ${Boost_LIBRARIES} ${CMAKE_DL_LIBS} ${link_param})
-setup_rpath(ecpbram)
+add_executable(${PROGRAM_PREFIX}ecpbram ${INCLUDE_FILES} tools/ecpbram.cpp "${CMAKE_BINARY_DIR}/generated/version.cpp")
+target_include_directories(${PROGRAM_PREFIX}ecpbram PRIVATE tools)
+target_compile_definitions(${PROGRAM_PREFIX}ecpbram PRIVATE TRELLIS_RPATH_DATADIR="${TRELLIS_RPATH_DATADIR}" TRELLIS_PREFIX="${CMAKE_INSTALL_PREFIX}" TRELLIS_PROGRAM_PREFIX="${PROGRAM_PREFIX}")
+target_link_libraries(${PROGRAM_PREFIX}ecpbram trellis ${Boost_LIBRARIES} ${CMAKE_DL_LIBS} ${link_param})
+setup_rpath(${PROGRAM_PREFIX}ecpbram)
 
-add_executable(ecppack ${INCLUDE_FILES} tools/ecppack.cpp "${CMAKE_BINARY_DIR}/generated/version.cpp")
-target_include_directories(ecppack PRIVATE tools)
-target_compile_definitions(ecppack PRIVATE TRELLIS_RPATH_DATADIR="${TRELLIS_RPATH_DATADIR}" TRELLIS_PREFIX="${CMAKE_INSTALL_PREFIX}")
-target_link_libraries(ecppack trellis ${Boost_LIBRARIES} ${CMAKE_DL_LIBS} ${link_param})
-setup_rpath(ecppack)
+add_executable(${PROGRAM_PREFIX}ecppack ${INCLUDE_FILES} tools/ecppack.cpp "${CMAKE_BINARY_DIR}/generated/version.cpp")
+target_include_directories(${PROGRAM_PREFIX}ecppack PRIVATE tools)
+target_compile_definitions(${PROGRAM_PREFIX}ecppack PRIVATE TRELLIS_RPATH_DATADIR="${TRELLIS_RPATH_DATADIR}" TRELLIS_PREFIX="${CMAKE_INSTALL_PREFIX}" TRELLIS_PROGRAM_PREFIX="${PROGRAM_PREFIX}")
+target_link_libraries(${PROGRAM_PREFIX}ecppack trellis ${Boost_LIBRARIES} ${CMAKE_DL_LIBS} ${link_param})
+setup_rpath(${PROGRAM_PREFIX}ecppack)
 
-add_executable(ecpunpack ${INCLUDE_FILES} tools/ecpunpack.cpp "${CMAKE_BINARY_DIR}/generated/version.cpp")
-target_include_directories(ecpunpack PRIVATE tools)
-target_compile_definitions(ecpunpack PRIVATE TRELLIS_RPATH_DATADIR="${TRELLIS_RPATH_DATADIR}" TRELLIS_PREFIX="${CMAKE_INSTALL_PREFIX}")
-target_link_libraries(ecpunpack trellis ${Boost_LIBRARIES} ${CMAKE_DL_LIBS} ${link_param})
-setup_rpath(ecpunpack)
+add_executable(${PROGRAM_PREFIX}ecpunpack ${INCLUDE_FILES} tools/ecpunpack.cpp "${CMAKE_BINARY_DIR}/generated/version.cpp")
+target_include_directories(${PROGRAM_PREFIX}ecpunpack PRIVATE tools)
+target_compile_definitions(${PROGRAM_PREFIX}ecpunpack PRIVATE TRELLIS_RPATH_DATADIR="${TRELLIS_RPATH_DATADIR}" TRELLIS_PREFIX="${CMAKE_INSTALL_PREFIX}" TRELLIS_PROGRAM_PREFIX="${PROGRAM_PREFIX}")
+target_link_libraries(${PROGRAM_PREFIX}ecpunpack trellis ${Boost_LIBRARIES} ${CMAKE_DL_LIBS} ${link_param})
+setup_rpath(${PROGRAM_PREFIX}ecpunpack)
 
-add_executable(ecppll ${INCLUDE_FILES} tools/ecppll.cpp "${CMAKE_BINARY_DIR}/generated/version.cpp")
-target_include_directories(ecppll PRIVATE tools)
-target_compile_definitions(ecppll PRIVATE TRELLIS_RPATH_DATADIR="${TRELLIS_RPATH_DATADIR}" TRELLIS_PREFIX="${CMAKE_INSTALL_PREFIX}")
-target_link_libraries(ecppll trellis ${Boost_LIBRARIES} ${CMAKE_DL_LIBS} ${link_param})
-setup_rpath(ecppll)
+add_executable(${PROGRAM_PREFIX}ecppll ${INCLUDE_FILES} tools/ecppll.cpp "${CMAKE_BINARY_DIR}/generated/version.cpp")
+target_include_directories(${PROGRAM_PREFIX}ecppll PRIVATE tools)
+target_compile_definitions(${PROGRAM_PREFIX}ecppll PRIVATE TRELLIS_RPATH_DATADIR="${TRELLIS_RPATH_DATADIR}" TRELLIS_PREFIX="${CMAKE_INSTALL_PREFIX}" TRELLIS_PROGRAM_PREFIX="${PROGRAM_PREFIX}")
+target_link_libraries(${PROGRAM_PREFIX}ecppll trellis ${Boost_LIBRARIES} ${CMAKE_DL_LIBS} ${link_param})
+setup_rpath(${PROGRAM_PREFIX}ecppll)
 
-add_executable(ecpmulti ${INCLUDE_FILES} tools/ecpmulti.cpp "${CMAKE_BINARY_DIR}/generated/version.cpp")
-target_include_directories(ecpmulti PRIVATE tools)
-target_compile_definitions(ecpmulti PRIVATE TRELLIS_RPATH_DATADIR="${TRELLIS_RPATH_DATADIR}" TRELLIS_PREFIX="${CMAKE_INSTALL_PREFIX}")
-target_link_libraries(ecpmulti trellis ${Boost_LIBRARIES} ${CMAKE_DL_LIBS} ${link_param})
-setup_rpath(ecpmulti)
+add_executable(${PROGRAM_PREFIX}ecpmulti ${INCLUDE_FILES} tools/ecpmulti.cpp "${CMAKE_BINARY_DIR}/generated/version.cpp")
+target_include_directories(${PROGRAM_PREFIX}ecpmulti PRIVATE tools)
+target_compile_definitions(${PROGRAM_PREFIX}ecpmulti PRIVATE TRELLIS_RPATH_DATADIR="${TRELLIS_RPATH_DATADIR}" TRELLIS_PREFIX="${CMAKE_INSTALL_PREFIX}" TRELLIS_PROGRAM_PREFIX="${PROGRAM_PREFIX}")
+target_link_libraries(${PROGRAM_PREFIX}ecpmulti trellis ${Boost_LIBRARIES} ${CMAKE_DL_LIBS} ${link_param})
+setup_rpath(${PROGRAM_PREFIX}ecpmulti)
 
 if (BUILD_SHARED)
-    install(TARGETS trellis ecpbram ecppack ecppll ecpunpack ecpmulti ${PythonInstallTarget}
-            LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}/trellis
+    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
             RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
 else()
-    install(TARGETS ecpbram ecppack ecpunpack ecppll ecpmulti
+    install(TARGETS ${PROGRAM_PREFIX}ecpbram ${PROGRAM_PREFIX}ecppack ${PROGRAM_PREFIX}ecpunpack ${PROGRAM_PREFIX}ecppll ${PROGRAM_PREFIX}ecpmulti
             RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
 endif()
-install(DIRECTORY ../database DESTINATION ${CMAKE_INSTALL_DATADIR}/trellis PATTERN ".git" EXCLUDE)
-install(DIRECTORY ../misc DESTINATION ${CMAKE_INSTALL_DATADIR}/trellis)
-install(DIRECTORY ../util/common DESTINATION ${CMAKE_INSTALL_DATADIR}/trellis/util)
-install(DIRECTORY ../timing/util DESTINATION ${CMAKE_INSTALL_DATADIR}/trellis/timing USE_SOURCE_PERMISSIONS)
+install(DIRECTORY ../database DESTINATION ${CMAKE_INSTALL_DATADIR}/${PROGRAM_PREFIX}trellis PATTERN ".git" EXCLUDE)
+install(DIRECTORY ../misc DESTINATION ${CMAKE_INSTALL_DATADIR}/${PROGRAM_PREFIX}trellis)
+install(DIRECTORY ../util/common DESTINATION ${CMAKE_INSTALL_DATADIR}/${PROGRAM_PREFIX}trellis/util)
+install(DIRECTORY ../timing/util DESTINATION ${CMAKE_INSTALL_DATADIR}/${PROGRAM_PREFIX}trellis/timing USE_SOURCE_PERMISSIONS)
diff --git a/libtrellis/include/DatabasePath.hpp b/libtrellis/include/DatabasePath.hpp
index 4063802..cab8a29 100644
--- a/libtrellis/include/DatabasePath.hpp
+++ b/libtrellis/include/DatabasePath.hpp
@@ -11,7 +11,7 @@
 std::string get_database_path()
 {
     boost::filesystem::path executable_path = boost::dll::program_location().parent_path();
-    boost::filesystem::path database_datadir_relative(TRELLIS_RPATH_DATADIR "/trellis/database");
+    boost::filesystem::path database_datadir_relative(TRELLIS_RPATH_DATADIR "/" TRELLIS_PROGRAM_PREFIX "trellis/database");
     std::string database_folder = (executable_path /= database_datadir_relative).string();
     return database_folder;
 }
diff --git a/libtrellis/tools/ecpbram.cpp b/libtrellis/tools/ecpbram.cpp
index 4c872fb..a1bc205 100644
--- a/libtrellis/tools/ecpbram.cpp
+++ b/libtrellis/tools/ecpbram.cpp
@@ -69,10 +69,11 @@
             hexfile.back().at(i) = true;
 }
 
-void parse_hexfile_line(const char *filename, int linenr, vector<vector<bool>> &hexfile, string &line)
+void parse_hexfile_line(const char *filename, int linenr, vector<vector<bool>> &hexfile, string &line, int &address)
 {
     vector<int> digits;
-
+    bool reading_address = false;
+    
     for (char c : line) {
         if ('0' <= c && c <= '9')
             digits.push_back(c - '0');
@@ -85,9 +86,29 @@
             digits.push_back(0);
         else if ('_' == c)
             ;
-        else if (' ' == c || '\t' == c || '\r' == c) {
-            push_back_bitvector(hexfile, digits);
-            digits.clear();
+	else if ('@' == c) {
+	    if (reading_address || !digits.empty())
+		goto error;
+	    else
+		reading_address = true;
+        } else if (' ' == c || '\t' == c || '\r' == c) {
+	    if (reading_address) {
+		int file_address = 0;
+		for (int i = 0; i < int(digits.size()); i++ ) {
+		    file_address <<= 4;
+		    file_address |= digits.at(i);
+		}
+		if (file_address != address) {
+		    fprintf(stderr, "Non-contiguous address (expected @%X) at line %d of %s: %s\n", address, linenr, filename, line.c_str());
+		    exit(1);
+		}
+	    } else {
+		push_back_bitvector(hexfile, digits);
+		if( !digits.empty() )
+		    address++;
+	    }
+	    digits.clear();
+	    reading_address = false;
         } else goto error;
     }
 
@@ -146,7 +167,7 @@
     if (vm.count("help")) {
     help:
         cerr << "Project Trellis - Open Source Tools for ECP5 FPGAs" << endl;
-        cerr << "ecpbram: ECP5 BRAM content initialization tool" << endl;
+        cerr << argv[0] << ": ECP5 BRAM content initialization tool" << endl;
         cerr << endl;
         cerr << "Copyright (C) 2019  Sylvain Munaut <tnt@246tNt.com>" << endl;
         cerr << "Copyright (C) 2016  Clifford Wolf <clifford@clifford.at>" << endl;
@@ -243,12 +264,12 @@
     vector<vector<bool>> to_hexfile;
 
     string line;
+    
+    for (int i = 1, address = 0; getline(from_hexfile_f, line); i++)
+        parse_hexfile_line(from_hexfile_n, i, from_hexfile, line, address);
 
-    for (int i = 1; getline(from_hexfile_f, line); i++)
-        parse_hexfile_line(from_hexfile_n, i, from_hexfile, line);
-
-    for (int i = 1; getline(to_hexfile_f, line); i++)
-        parse_hexfile_line(to_hexfile_n, i, to_hexfile, line);
+    for (int i = 1, address = 0; getline(to_hexfile_f, line); i++)
+        parse_hexfile_line(to_hexfile_n, i, to_hexfile, line, address);
 
     if (to_hexfile.size() > 0 && from_hexfile.size() > to_hexfile.size()) {
         if (verbose)
diff --git a/libtrellis/tools/ecpmulti.cpp b/libtrellis/tools/ecpmulti.cpp
index 16d6675..83232e1 100644
--- a/libtrellis/tools/ecpmulti.cpp
+++ b/libtrellis/tools/ecpmulti.cpp
@@ -82,7 +82,7 @@
         help:
         cerr << "Project Trellis - Open Source Tools for ECP5 FPGAs" << endl;
         cerr << "Version " << git_describe_str << endl;
-        cerr << "ecpmulti: ECP5 multiboot bitstream assembler" << endl;
+        cerr << argv[0] << ": ECP5 multiboot bitstream assembler" << endl;
         cerr << endl;
         cerr << "Copyright (C) 2019 Jens Andersen <jens.andersen@gmail.com>" << endl;
         cerr << endl;
diff --git a/libtrellis/tools/ecppack.cpp b/libtrellis/tools/ecppack.cpp
index f060468..d6aea40 100644
--- a/libtrellis/tools/ecppack.cpp
+++ b/libtrellis/tools/ecppack.cpp
@@ -75,11 +75,11 @@
 help:
         cerr << "Project Trellis - Open Source Tools for ECP5 FPGAs" << endl;
         cerr << "Version " << git_describe_str << endl;
-        cerr << "ecppack: ECP5 bitstream packer" << endl;
+        cerr << argv[0] << ": ECP5 bitstream packer" << endl;
         cerr << endl;
         cerr << "Copyright (C) 2018 David Shah <david@symbioticeda.com>" << endl;
         cerr << endl;
-        cerr << "Usage: ecppack input.config [output.bit] [options]" << endl;
+        cerr << "Usage: " << argv[0] << " input.config [output.bit] [options]" << endl;
         cerr << options << endl;
         return vm.count("help") ? 0 : 1;
     }
diff --git a/libtrellis/tools/ecppll.cpp b/libtrellis/tools/ecppll.cpp
index f7b01d3..13e6b26 100644
--- a/libtrellis/tools/ecppll.cpp
+++ b/libtrellis/tools/ecppll.cpp
@@ -124,7 +124,7 @@
 
   if(vm.count("help")){
     cerr << "Project Trellis - Open Source Tools for ECP5 FPGAs" << endl;
-    cerr << "ecppll: ECP5 PLL Configuration Calculator" << endl;
+    cerr << argv[0] << ": ECP5 PLL Configuration Calculator" << endl;
     cerr << "Version " << git_describe_str << endl;
     cerr << endl;
     cerr << "This tool is experimental! Use at your own risk!" << endl;
diff --git a/libtrellis/tools/ecpunpack.cpp b/libtrellis/tools/ecpunpack.cpp
index 77e2276..a5752a8 100644
--- a/libtrellis/tools/ecpunpack.cpp
+++ b/libtrellis/tools/ecpunpack.cpp
@@ -51,11 +51,11 @@
 help:
         cerr << "Project Trellis - Open Source Tools for ECP5 FPGAs" << endl;
         cerr << "Version " << git_describe_str << endl;
-        cerr << "ecpunpack: ECP5 bitstream to text config converter" << endl;
+        cerr << argv[0] << ": ECP5 bitstream to text config converter" << endl;
         cerr << endl;
         cerr << "Copyright (C) 2018 David Shah <david@symbioticeda.com>" << endl;
         cerr << endl;
-        cerr << "Usage: ecpunpack input.bit [output.config] [options]" << endl;
+        cerr << "Usage: " << argv[0] << " input.bit [output.config] [options]" << endl;
         cerr << options << endl;
         return vm.count("help") ? 0 : 1;
     }