From 1dc1164dce88fade762956c1067aeb97fa3c0f9a Mon Sep 17 00:00:00 2001
From: whitequark <whitequark@whitequark.org>
Date: Wed, 24 Jun 2020 15:44:45 +0000
Subject: CMake: rewrite chipdb handling from ground up.

---
 ecp5/CMakeLists.txt     |  92 +++++++++++++++++++++++++++++
 ecp5/arch.cc            |   4 +-
 ecp5/arch.h             |   2 +-
 ecp5/family.cmake       | 152 ++++++++++++++----------------------------------
 ecp5/resource/chipdb.rc |   6 +-
 ecp5/trellis_import.py  |  14 +++--
 6 files changed, 151 insertions(+), 119 deletions(-)
 create mode 100644 ecp5/CMakeLists.txt

(limited to 'ecp5')

diff --git a/ecp5/CMakeLists.txt b/ecp5/CMakeLists.txt
new file mode 100644
index 00000000..eaa33b6f
--- /dev/null
+++ b/ecp5/CMakeLists.txt
@@ -0,0 +1,92 @@
+cmake_minimum_required(VERSION 3.3)
+project(chipdb-ecp5 NONE)
+
+set(ALL_ECP5_DEVICES 25k 45k 85k)
+set(ECP5_DEVICES ${ALL_ECP5_DEVICES} CACHE STRING
+    "Include support for these ECP5 devices (available: ${ALL_ECP5_DEVICES})")
+message(STATUS "Enabled ECP5 devices: ${ECP5_DEVICES}")
+
+if(DEFINED ECP5_CHIPDB)
+    add_custom_target(chipdb-ecp5-bbas ALL)
+else()
+    find_package(PythonInterp 3.5 REQUIRED)
+
+    # shared among all families
+    set(SERIALIZE_CHIPDBS TRUE CACHE BOOL
+        "Serialize device data preprocessing to minimize memory use")
+
+    set(TRELLIS_PROGRAM_PREFIX "" CACHE STRING
+        "Trellis name prefix")
+    if(TRELLIS_PROGRAM_PREFIX)
+        message(STATUS "Trellis program prefix: ${TRELLIS_PROGRAM_PREFIX}")
+    endif()
+
+    set(TRELLIS_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX} CACHE STRING
+        "Trellis install prefix")
+    message(STATUS "Trellis install prefix: ${TRELLIS_INSTALL_PREFIX}")
+
+    if(NOT DEFINED TRELLIS_LIBDIR)
+        if(WIN32)
+            set(pytrellis_lib pytrellis.pyd)
+        else()
+            set(pytrellis_lib pytrellis${CMAKE_SHARED_LIBRARY_SUFFIX})
+        endif()
+        find_path(TRELLIS_LIBDIR ${pytrellis_lib}
+            HINTS ${TRELLIS_INSTALL_PREFIX}/lib/${TRELLIS_PROGRAM_PREFIX}trellis
+            PATHS ${CMAKE_SYSTEM_LIBRARY_PATH} ${CMAKE_LIBRARY_PATH}
+            PATH_SUFFIXES ${TRELLIS_PROGRAM_PREFIX}trellis
+            DOC "Location of the pytrellis library")
+        if(NOT TRELLIS_LIBDIR)
+            message(FATAL_ERROR "Failed to locate the pytrellis library")
+        endif()
+    endif()
+    message(STATUS "Trellis library directory: ${TRELLIS_LIBDIR}")
+
+    if(NOT DEFINED TRELLIS_DATADIR)
+        set(TRELLIS_DATADIR ${TRELLIS_INSTALL_PREFIX}/share/${TRELLIS_PROGRAM_PREFIX}trellis)
+    endif()
+    message(STATUS "Trellis data directory: ${TRELLIS_DATADIR}")
+
+    set(all_device_bbas)
+    file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/chipdb)
+    foreach(device ${ECP5_DEVICES})
+        if(NOT device IN_LIST ALL_ECP5_DEVICES)
+            message(FATAL_ERROR "Device ${device} is not a supported ECP5 device")
+        endif()
+
+        set(device_bba chipdb/chipdb-${device}.bba)
+        add_custom_command(
+            OUTPUT ${device_bba}
+            COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/trellis_import.py
+                -L ${TRELLIS_LIBDIR}
+                -L ${TRELLIS_DATADIR}/util/common
+                -L ${TRELLIS_DATADIR}/timing/util
+                -p ${CMAKE_CURRENT_SOURCE_DIR}/constids.inc
+                -g ${CMAKE_CURRENT_SOURCE_DIR}/gfx.h
+                ${device}
+                > ${device_bba}.new
+            # atomically update
+            COMMAND ${CMAKE_COMMAND} -E rename ${device_bba}.new ${device_bba}
+            DEPENDS
+                ${CMAKE_CURRENT_SOURCE_DIR}/trellis_import.py
+                ${CMAKE_CURRENT_SOURCE_DIR}/constids.inc
+                ${CMAKE_CURRENT_SOURCE_DIR}/gfx.h
+                ${PREVIOUS_CHIPDB_TARGET}
+            VERBATIM)
+        list(APPEND all_device_bbas ${device_bba})
+        if(SERIALIZE_CHIPDBS)
+            set(PREVIOUS_CHIPDB_TARGET ${CMAKE_CURRENT_BINARY_DIR}/${device_bba})
+        endif()
+    endforeach()
+
+    add_custom_target(chipdb-ecp5-bbas ALL DEPENDS ${all_device_bbas})
+
+    get_directory_property(has_parent PARENT_DIRECTORY)
+    if(has_parent)
+        set(ECP5_CHIPDB ${CMAKE_CURRENT_BINARY_DIR}/chipdb PARENT_SCOPE)
+        # serialize chipdb build across multiple architectures
+        set(PREVIOUS_CHIPDB_TARGET chipdb-ecp5-bbas PARENT_SCOPE)
+    else()
+        message(STATUS "Build nextpnr with -DECP5_CHIPDB=${CMAKE_CURRENT_BINARY_DIR}")
+    endif()
+endif()
diff --git a/ecp5/arch.cc b/ecp5/arch.cc
index 3c00099f..f947783e 100644
--- a/ecp5/arch.cc
+++ b/ecp5/arch.cc
@@ -62,7 +62,7 @@ void IdString::initialize_arch(const BaseCtx *ctx)
 
 static const ChipInfoPOD *get_chip_info(const RelPtr<ChipInfoPOD> *ptr) { return ptr->get(); }
 
-#if defined(_MSC_VER)
+#if defined(WIN32)
 void load_chipdb();
 #endif
 
@@ -97,7 +97,7 @@ void load_chipdb()
 
 Arch::Arch(ArchArgs args) : args(args)
 {
-#if defined(_MSC_VER) || defined(EXTERNAL_CHIPDB_ROOT)
+#if defined(WIN32) || defined(EXTERNAL_CHIPDB_ROOT)
     load_chipdb();
 #endif
 #ifdef LFE5U_45F_ONLY
diff --git a/ecp5/arch.h b/ecp5/arch.h
index d57b5bc0..c13f2041 100644
--- a/ecp5/arch.h
+++ b/ecp5/arch.h
@@ -207,7 +207,7 @@ NPNR_PACKED_STRUCT(struct ChipInfoPOD {
     RelPtr<SpeedGradePOD> speed_grades;
 });
 
-#if defined(_MSC_VER) || defined(EXTERNAL_CHIPDB_ROOT)
+#if defined(WIN32) || defined(EXTERNAL_CHIPDB_ROOT)
 extern const char *chipdb_blob_25k;
 extern const char *chipdb_blob_45k;
 extern const char *chipdb_blob_85k;
diff --git a/ecp5/family.cmake b/ecp5/family.cmake
index 247a307a..0f96811a 100644
--- a/ecp5/family.cmake
+++ b/ecp5/family.cmake
@@ -1,112 +1,48 @@
-if (NOT EXTERNAL_CHIPDB)
-    set(devices 25k 45k 85k)
-
-    set(TRELLIS_PROGRAM_PREFIX "" CACHE STRING "Name prefix for trellis")
-
-    if (NOT DEFINED TRELLIS_INSTALL_PREFIX)
-        message(STATUS "TRELLIS_INSTALL_PREFIX not defined using -DTRELLIS_INSTALL_PREFIX=/path-prefix/to/prjtrellis-installation. Defaulted to ${CMAKE_INSTALL_PREFIX}")
-        set(TRELLIS_INSTALL_PREFIX ${CMAKE_INSTALL_PREFIX})
-    endif()
-
-    if (NOT DEFINED PYTRELLIS_LIBDIR)
-        find_library(PYTRELLIS pytrellis.so
-            PATHS ${TRELLIS_INSTALL_PREFIX}/lib/${TRELLIS_PROGRAM_PREFIX}trellis
-            PATH_SUFFIXES ${TRELLIS_PROGRAM_PREFIX}trellis
-            DOC "Location of pytrellis library")
-
-        if ("${PYTRELLIS}" STREQUAL "PYTRELLIS-NOTFOUND")
-            message(FATAL_ERROR "Failed to locate pytrellis library!")
-        endif()
-
-        get_filename_component(PYTRELLIS_LIBDIR ${PYTRELLIS} DIRECTORY)
+add_subdirectory(${family})
+message(STATUS "Using ECP5 chipdb: ${ECP5_CHIPDB}")
+
+set(chipdb_sources)
+set(chipdb_binaries)
+file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${family}/chipdb)
+foreach(device ${ECP5_DEVICES})
+    set(chipdb_bba ${ECP5_CHIPDB}/chipdb-${device}.bba)
+    set(chipdb_bin ${family}/chipdb/chipdb-${device}.bin)
+    set(chipdb_cc  ${family}/chipdb/chipdb-${device}.cc)
+    if(BBASM_MODE STREQUAL "binary")
+        add_custom_command(
+            OUTPUT ${chipdb_bin}
+            COMMAND bbasm ${BBASM_ENDIAN_FLAG} ${chipdb_bba} ${chipdb_bin}
+            DEPENDS bbasm chipdb-${family}-bbas ${chipdb_bba})
+        list(APPEND chipdb_binaries ${chipdb_bin})
+    elseif(BBASM_MODE STREQUAL "embed")
+        add_custom_command(
+            OUTPUT ${chipdb_cc} ${chipdb_bin}
+            COMMAND bbasm ${BBASM_ENDIAN_FLAG} --e ${chipdb_bba} ${chipdb_cc} ${chipdb_bin}
+            DEPENDS bbasm chipdb-${family}-bbas ${chipdb_bba})
+        list(APPEND chipdb_sources ${chipdb_cc})
+        list(APPEND chipdb_binaries ${chipdb_bin})
+    elseif(BBASM_MODE STREQUAL "string")
+        add_custom_command(
+            OUTPUT ${chipdb_cc}
+            COMMAND bbasm ${BBASM_ENDIAN_FLAG} --c ${chipdb_bba} ${chipdb_cc}
+            DEPENDS bbasm chipdb-${family}-bbas ${chipdb_bba})
+        list(APPEND chipdb_sources ${chipdb_cc})
     endif()
+endforeach()
+if(WIN32)
+    list(APPEND chipdb_sources
+        ${CMAKE_CURRENT_SOURCE_DIR}/${family}/resource/embed.cc
+        ${CMAKE_CURRENT_SOURCE_DIR}/${family}/resource/chipdb.rc)
+endif()
 
-    set(DB_PY ${CMAKE_CURRENT_SOURCE_DIR}/ecp5/trellis_import.py)
-
-    file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/ecp5/chipdbs/)
-    add_library(ecp5_chipdb OBJECT ${CMAKE_CURRENT_BINARY_DIR}/ecp5/chipdbs/)
-    target_compile_definitions(ecp5_chipdb PRIVATE NEXTPNR_NAMESPACE=nextpnr_${family})
-    target_include_directories(ecp5_chipdb PRIVATE ${family}/)
+add_custom_target(chipdb-${family}-bins DEPENDS ${chipdb_sources} ${chipdb_binaries})
 
-    if (CMAKE_HOST_WIN32)
-        set(ENV_CMD ${CMAKE_COMMAND} -E env "PYTHONPATH=\"${PYTRELLIS_LIBDIR}\;${TRELLIS_INSTALL_PREFIX}/share/${TRELLIS_PROGRAM_PREFIX}trellis/util/common\;${TRELLIS_INSTALL_PREFIX}/share/${TRELLIS_PROGRAM_PREFIX}trellis/timing/util\"")
-    else()
-        set(ENV_CMD ${CMAKE_COMMAND} -E env "PYTHONPATH=${PYTRELLIS_LIBDIR}\:${TRELLIS_INSTALL_PREFIX}/share/${TRELLIS_PROGRAM_PREFIX}trellis/util/common:${TRELLIS_INSTALL_PREFIX}/share/${TRELLIS_PROGRAM_PREFIX}trellis/timing/util")
-    endif()
+add_library(chipdb-${family} OBJECT ${ICE40_CHIPDB} ${chipdb_sources})
+add_dependencies(chipdb-${family} chipdb-${family}-bins)
+target_compile_options(chipdb-${family} PRIVATE -g0 -O0 -w)
+target_compile_definitions(chipdb-${family} PRIVATE NEXTPNR_NAMESPACE=nextpnr_${family})
+target_include_directories(chipdb-${family} PRIVATE ${family})
 
-    if (MSVC)
-        target_sources(ecp5_chipdb PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/ecp5/resource/embed.cc)
-        set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/ecp5/resources/chipdb.rc PROPERTIES LANGUAGE RC)
-        set(PREV_DEV_CC_BBA_DB)
-        foreach (dev ${devices})
-            set(DEV_CC_DB ${CMAKE_CURRENT_BINARY_DIR}/ecp5/chipdbs/chipdb-${dev}.bin)
-            set(DEV_CC_BBA_DB ${CMAKE_CURRENT_BINARY_DIR}/ecp5/chipdbs/chipdb-${dev}.bba)
-            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)
-                add_custom_command(OUTPUT ${DEV_CC_DB}
-                    COMMAND bbasm ${BBASM_ENDIAN_FLAG} ${PREGENERATED_BBA_PATH}/chipdb-${dev}.bba ${DEV_CC_DB}
-                    )
-            else()
-                add_custom_command(OUTPUT ${DEV_CC_BBA_DB}
-                    COMMAND ${ENV_CMD} ${PYTHON_EXECUTABLE} ${DB_PY} -p ${DEV_CONSTIDS_INC} -g ${DEV_GFXH} ${dev} > ${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 ${BBASM_ENDIAN_FLAG} ${DEV_CC_BBA_DB} ${DEV_CC_DB}
-                    DEPENDS bbasm ${DEV_CC_BBA_DB}
-                    )
-            endif()
-            if (SERIALIZE_CHIPDB)
-                set(PREV_DEV_CC_BBA_DB ${DEV_CC_BBA_DB})
-            endif()
-            target_sources(ecp5_chipdb PRIVATE ${DEV_CC_DB})
-            set_source_files_properties(${DEV_CC_DB} PROPERTIES HEADER_FILE_ONLY TRUE)
-            foreach (target ${family_targets})
-                target_sources(${target} PRIVATE $<TARGET_OBJECTS:ecp5_chipdb> ${CMAKE_CURRENT_SOURCE_DIR}/ecp5/resource/chipdb.rc)
-            endforeach()
-        endforeach()
-    else()
-        target_compile_options(ecp5_chipdb PRIVATE -g0 -O0 -w)
-        set(PREV_DEV_CC_BBA_DB)
-        foreach (dev ${devices})
-            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)
-                add_custom_command(OUTPUT ${DEV_CC_DB}
-                    COMMAND bbasm --c ${BBASM_ENDIAN_FLAG} ${PREGENERATED_BBA_PATH}/chipdb-${dev}.bba ${DEV_CC_DB}.new
-                    COMMAND mv ${DEV_CC_DB}.new ${DEV_CC_DB}
-                    )
-            else()
-                add_custom_command(OUTPUT ${DEV_CC_BBA_DB}
-                    COMMAND ${ENV_CMD} ${PYTHON_EXECUTABLE} ${DB_PY} -p ${DEV_CONSTIDS_INC} -g ${DEV_GFXH} ${dev} > ${DEV_CC_BBA_DB}.new
-                    COMMAND mv ${DEV_CC_BBA_DB}.new ${DEV_CC_BBA_DB}
-                    DEPENDS ${DB_PY} ${DEV_CONSTIDS_INC} ${DEV_GFXH} ${PREV_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})
-            endif()
-            target_sources(ecp5_chipdb PRIVATE ${DEV_CC_DB})
-            foreach (target ${family_targets})
-                target_sources(${target} PRIVATE $<TARGET_OBJECTS:ecp5_chipdb>)
-            endforeach()
-        endforeach()
-    endif()
-endif()
+foreach(family_target ${family_targets})
+    target_sources(${family_target} PRIVATE $<TARGET_OBJECTS:chipdb-${family}>)
+endforeach()
diff --git a/ecp5/resource/chipdb.rc b/ecp5/resource/chipdb.rc
index 7191f581..60f690c6 100644
--- a/ecp5/resource/chipdb.rc
+++ b/ecp5/resource/chipdb.rc
@@ -1,5 +1,5 @@
 #include "resource.h"
 
-IDR_CHIPDB_25K  BINARYFILE "..\chipdbs\chipdb-25k.bin"
-IDR_CHIPDB_45K  BINARYFILE "..\chipdbs\chipdb-45k.bin"
-IDR_CHIPDB_88K  BINARYFILE "..\chipdbs\chipdb-85k.bin"
+IDR_CHIPDB_25K  BINARYFILE "ecp5/chipdb/chipdb-25k.bin"
+IDR_CHIPDB_45K  BINARYFILE "ecp5/chipdb/chipdb-45k.bin"
+IDR_CHIPDB_88K  BINARYFILE "ecp5/chipdb/chipdb-85k.bin"
diff --git a/ecp5/trellis_import.py b/ecp5/trellis_import.py
index a21c4b3d..b591e09f 100755
--- a/ecp5/trellis_import.py
+++ b/ecp5/trellis_import.py
@@ -1,10 +1,7 @@
 #!/usr/bin/env python3
-import pytrellis
-import database
 import argparse
 import json
-import pip_classes
-import timing_dbs
+import sys
 from os import path
 
 location_types = dict()
@@ -17,8 +14,15 @@ parser = argparse.ArgumentParser(description="import ECP5 routing and bels from
 parser.add_argument("device", type=str, help="target device")
 parser.add_argument("-p", "--constids", type=str, help="path to constids.inc")
 parser.add_argument("-g", "--gfxh", type=str, help="path to gfx.h")
+parser.add_argument("-L", "--libdir", type=str, action="append", help="extra Python library path")
 args = parser.parse_args()
 
+sys.path += args.libdir
+import pytrellis
+import database
+import pip_classes
+import timing_dbs
+
 with open(args.gfxh) as f:
     state = 0
     for line in f:
@@ -437,7 +441,7 @@ def write_database(dev_name, chip, ddrg, endianness):
                 bba.u32(constids[wire_type(ddrg.to_str(wire.name))], "type")
                 if ("TILE_WIRE_" + ddrg.to_str(wire.name)) in gfx_wire_ids:
                     bba.u32(gfx_wire_ids["TILE_WIRE_" + ddrg.to_str(wire.name)], "tile_wire")
-                else:                    
+                else:
                     bba.u32(0, "tile_wire")
                 bba.u32(len(wire.arcsUphill), "num_uphill")
                 bba.u32(len(wire.arcsDownhill), "num_downhill")
-- 
cgit v1.2.3