Files
pico/projects/Z80/CMakeLists.txt

533 lines
17 KiB
CMake
Vendored

# Z80 - CMakeLists.txt
# ______ ______ ______
# /\___ \/\ __ \\ __ \
# \/__/ /\_\ __ \\ \/\ \
# /\_____\\_____\\_____\
# Zilog \/_____//_____//_____/ CPU Emulator
# Copyright (C) 1999-2026 Manuel Sainz de Baranda y Goñi.
# Released under the terms of the GNU Lesser General Public License v3.
cmake_minimum_required(
# 3.14: install(TARGETS ARCHIVE [DESTINATION])
VERSION 3.14...${CMAKE_VERSION})
if( CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR AND
NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES
)
set(CMAKE_BUILD_TYPE Release)
endif()
add_compile_options(-Wall
-Wno-format # int != int32_t as far as the compiler is concerned because gcc has int32_t as long int
-Wno-unused-function # we have some for the docs that aren't called
-Ofast
)
file(READ "${CMAKE_CURRENT_SOURCE_DIR}/API/Z80.h" _)
string(REGEX MATCH ".*Z80_LIBRARY_VERSION_STRING \"([^\"]+)\".*" _ ${_})
project(Z80
VERSION ${CMAKE_MATCH_1}
LANGUAGES C
DESCRIPTION "Zilog Z80 CPU emulator"
HOMEPAGE_URL "https://zxe.io/software/Z80")
unset(_)
execute_process(
COMMAND ${CMAKE_COMMAND} -E echo
"${PROJECT_NAME} v${PROJECT_VERSION}")
include(GNUInstallDirs)
set(${PROJECT_NAME}_DEPOT_LOCATION
"http://zxe.io/depot" CACHE STRING
"${PROJECT_NAME}: \
Directory or URL of the depot containing the test files.")
option(${PROJECT_NAME}_FETCH_TEST_FILES
"${PROJECT_NAME}: \
Copy or download the test files from the depot to the build directory."
NO)
set(${PROJECT_NAME}_INSTALL_CMAKEDIR
"${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}" CACHE STRING
"${PROJECT_NAME}: \
Directory in which to install the CMake config-file package.")
set(${PROJECT_NAME}_INSTALL_PKGCONFIGDIR
"${CMAKE_INSTALL_LIBDIR}/pkgconfig" CACHE STRING
"${PROJECT_NAME}: \
Directory in which to install the pkg-config file.")
set(${PROJECT_NAME}_NOSTDLIB_FLAGS
"Auto" CACHE STRING
"${PROJECT_NAME}: \
Linker flags used to avoid linking against system libraries.")
option(${PROJECT_NAME}_OBJECT_LIBS
"${PROJECT_NAME}: \
Build the emulator as an object library."
NO)
set(${PROJECT_NAME}_SPHINX_HTML_THEME
"" CACHE STRING
"${PROJECT_NAME}: \
Sphinx theme for the documentation in HTML format.")
option(${PROJECT_NAME}_WITH_CMAKE_SUPPORT
"${PROJECT_NAME}: \
Generate and install the CMake config-file package."
NO)
option(${PROJECT_NAME}_WITH_HTML_DOCUMENTATION
"${PROJECT_NAME}: \
Build and install the documentation in HTML format."
NO)
option(${PROJECT_NAME}_WITH_PDF_DOCUMENTATION
"${PROJECT_NAME}: \
Build and install the documentation in PDF format."
NO)
option(${PROJECT_NAME}_WITH_PKGCONFIG_SUPPORT
"${PROJECT_NAME}: \
Generate and install the pkg-config file."
NO)
option(${PROJECT_NAME}_WITH_STANDARD_DOCUMENTS
"${PROJECT_NAME}: \
Install the standard text documents distributed with the package: \
AUTHORS, COPYING, COPYING.LESSER, HISTORY, README and THANKS."
NO)
option(${PROJECT_NAME}_WITH_STEP_TESTING_TOOL
"${PROJECT_NAME}: \
Build `step-test-${PROJECT_NAME}`, a tool for unit tests in JSON format."
NO)
option(${PROJECT_NAME}_WITH_TESTING_TOOL
"${PROJECT_NAME}: \
Build `test-${PROJECT_NAME}`, a tool that runs various Z80-specific tests for \
CP/M and ZX Spectrum."
NO)
option(${PROJECT_NAME}_WITH_EXECUTE
"${PROJECT_NAME}: \
Build the implementation of the `z80_execute` function."
NO)
option(${PROJECT_NAME}_WITH_FULL_IM0
"${PROJECT_NAME}: \
Build the full implementation of the interrupt mode 0 rather than the \
reduced one."
NO)
option(${PROJECT_NAME}_WITH_IM0_RETX_NOTIFICATIONS
"${PROJECT_NAME}: \
Enable optional notifications for any `reti` or `retn` instruction \
executed during the interrupt mode 0 response."
NO)
option(${PROJECT_NAME}_WITH_PARITY_COMPUTATION
"${PROJECT_NAME}: \
Enable actual parity calculation for the P/V flag instead of using a \
table of precomputed values (NOT RECOMMENDED for production builds)."
NO)
option(${PROJECT_NAME}_WITH_PRECOMPUTED_DAA
"${PROJECT_NAME}: \
Use a table of precomputed values to emulate the `daa` instruction (NOT \
RECOMMENDED for production builds)."
NO)
option(${PROJECT_NAME}_WITH_Q
"${PROJECT_NAME}: \
Build the implementation of Q."
NO)
option(${PROJECT_NAME}_WITH_SPECIAL_RESET
"${PROJECT_NAME}: \
Build the implementation of the special RESET."
NO)
option(${PROJECT_NAME}_WITH_RESET_SIGNAL
"${PROJECT_NAME}: \
Build the implementation of the external reset signal check. When enabled, a \
pointer to a volatile byte (reset_signal) is checked at every instruction \
boundary. A non-zero value causes z80_run to exit immediately, allowing \
hardware-in-the-loop emulators to respond to a physical RESET line."
NO)
option(${PROJECT_NAME}_WITH_UNOFFICIAL_RETI
"${PROJECT_NAME}: \
Configure the undocumented instructions ED5Dh, ED6Dh and ED7Dh as `reti` \
instead of `retn`."
NO)
option(${PROJECT_NAME}_WITH_ZILOG_NMOS_LD_A_IR_BUG
"${PROJECT_NAME}: \
Build the implementation of the bug affecting the Zilog Z80 NMOS, which \
causes the P/V flag to be reset when a maskable interrupt is accepted \
during the execution of the `ld a,{i|r}` instructions."
NO)
option(${PROJECT_NAME}_WITH_CODE_GENERATION_TOOLS
"${PROJECT_NAME}: \
Build the tools that have been used to generate parts of the source code."
NO)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMake")
find_package(Zeta REQUIRED)
if(${PROJECT_NAME}_OBJECT_LIBS)
add_library(${PROJECT_NAME} OBJECT)
else()
if(DEFINED ${PROJECT_NAME}_SHARED_LIBS)
set(BUILD_SHARED_LIBS ${${PROJECT_NAME}_SHARED_LIBS})
endif()
add_library(${PROJECT_NAME})
endif()
target_sources(
${PROJECT_NAME} PRIVATE
"${CMAKE_CURRENT_SOURCE_DIR}/API/Z80.h"
"${CMAKE_CURRENT_SOURCE_DIR}/sources/Z80.c")
set_target_properties(
${PROJECT_NAME} PROPERTIES
C_STANDARD 99
C_STANDARD_REQUIRED NO
VERSION ${PROJECT_VERSION}
SOVERSION ${PROJECT_VERSION_MAJOR}
DEBUG_POSTFIX "-debug"
PUBLIC_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/API/Z80.h")
target_link_libraries(${PROJECT_NAME} PUBLIC Zeta)
target_include_directories(
${PROJECT_NAME} PUBLIC
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/API>"
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>")
if(${PROJECT_NAME}_OBJECT_LIBS OR NOT BUILD_SHARED_LIBS)
target_compile_definitions(${PROJECT_NAME} PUBLIC Z80_STATIC)
else()
if(WIN32)
if(PROJECT_VERSION_PATCH STREQUAL "")
set(PROJECT_VERSION_PATCH 0)
endif()
file(READ "${CMAKE_CURRENT_SOURCE_DIR}/README" _)
string(REGEX MATCH ".*Copyright \\(C\\) ([^ ]+) (([^. \t\n]+ ?)*[^. \t\n]+).*" _ ${_})
set(RC_COPYRIGHT_YEAR ${CMAKE_MATCH_1})
set(RC_AUTHOR ${CMAKE_MATCH_2})
unset(_)
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/sources/Z80.rc.in"
"${CMAKE_CURRENT_BINARY_DIR}/Z80.rc"
@ONLY)
unset(RC_COPYRIGHT_YEAR)
unset(RC_AUTHOR)
target_sources(${PROJECT_NAME} PRIVATE "${CMAKE_CURRENT_BINARY_DIR}/Z80.rc")
endif()
if(${PROJECT_NAME}_NOSTDLIB_FLAGS STREQUAL "Auto")
if(MSVC)
target_compile_definitions(${PROJECT_NAME} PRIVATE Z80_WITH_DLL_MAIN_CRT_STARTUP)
target_link_options(${PROJECT_NAME} PRIVATE "/NODEFAULTLIB")
elseif(APPLE)
if(CMAKE_C_COMPILER_ID MATCHES "^(AppleClang|Clang|GNU)$")
target_link_options(${PROJECT_NAME} PRIVATE "LINKER:-dead_strip_dylibs")
endif()
elseif(CMAKE_C_COMPILER_ID MATCHES "^(ARMClang|Clang|GNU|Intel|TinyCC|XL|XLClang)$")
target_link_options(${PROJECT_NAME} PRIVATE "-nostdlib")
elseif(CMAKE_C_COMPILER_ID MATCHES "PGI")
target_link_options(${PROJECT_NAME} PRIVATE "-Mnostdlib")
elseif(CMAKE_C_COMPILER_ID MATCHES "SunPro")
target_link_options(${PROJECT_NAME} PRIVATE "-xnolib")
endif()
elseif(NOT ${PROJECT_NAME}_NOSTDLIB_FLAGS STREQUAL "")
target_link_options(${PROJECT_NAME} PRIVATE ${${PROJECT_NAME}_NOSTDLIB_FLAGS})
endif()
endif()
target_compile_definitions(
${PROJECT_NAME} PRIVATE
$<$<BOOL:${${PROJECT_NAME}_WITH_EXECUTE}>:Z80_WITH_EXECUTE>
$<$<BOOL:${${PROJECT_NAME}_WITH_FULL_IM0}>:Z80_WITH_FULL_IM0>
$<$<BOOL:${${PROJECT_NAME}_WITH_IM0_RETX_NOTIFICATIONS}>:Z80_WITH_IM0_RETX_NOTIFICATIONS>
$<$<BOOL:${${PROJECT_NAME}_WITH_PARITY_COMPUTATION}>:Z80_WITH_PARITY_COMPUTATION>
$<$<BOOL:${${PROJECT_NAME}_WITH_PRECOMPUTED_DAA}>:Z80_WITH_PRECOMPUTED_DAA>
$<$<BOOL:${${PROJECT_NAME}_WITH_Q}>:Z80_WITH_Q>
$<$<BOOL:${${PROJECT_NAME}_WITH_RESET_SIGNAL}>:Z80_WITH_RESET_SIGNAL>
$<$<BOOL:${${PROJECT_NAME}_WITH_SPECIAL_RESET}>:Z80_WITH_SPECIAL_RESET>
$<$<BOOL:${${PROJECT_NAME}_WITH_UNOFFICIAL_RETI}>:Z80_WITH_UNOFFICIAL_RETI>
$<$<BOOL:${${PROJECT_NAME}_WITH_ZILOG_NMOS_LD_A_IR_BUG}>:Z80_WITH_ZILOG_NMOS_LD_A_IR_BUG>)
install(TARGETS ${PROJECT_NAME}
EXPORT ${PROJECT_NAME}_Targets
RUNTIME COMPONENT ${PROJECT_NAME}_Runtime
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
COMPONENT ${PROJECT_NAME}_Runtime
NAMELINK_COMPONENT ${PROJECT_NAME}_Development
ARCHIVE COMPONENT ${PROJECT_NAME}_Development
PUBLIC_HEADER
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
COMPONENT ${PROJECT_NAME}_Development)
if(NOT ${PROJECT_NAME}_OBJECT_LIBS)
if(${PROJECT_NAME}_WITH_CMAKE_SUPPORT)
include(CMakePackageConfigHelpers)
if(BUILD_SHARED_LIBS)
set(_type Shared)
else()
set(_type Static)
endif()
install(EXPORT ${PROJECT_NAME}_Targets
DESTINATION "${${PROJECT_NAME}_INSTALL_CMAKEDIR}"
FILE ${PROJECT_NAME}${_type}Targets.cmake
COMPONENT ${PROJECT_NAME}_Development)
unset(_type)
write_basic_package_version_file(
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake"
VERSION ${PROJECT_VERSION}
COMPATIBILITY SameMajorVersion)
configure_package_config_file(
"${CMAKE_CURRENT_SOURCE_DIR}/support/${PROJECT_NAME}Config.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
INSTALL_DESTINATION "${${PROJECT_NAME}_INSTALL_CMAKEDIR}")
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake"
DESTINATION "${${PROJECT_NAME}_INSTALL_CMAKEDIR}"
COMPONENT ${PROJECT_NAME}_Development)
endif()
if(${PROJECT_NAME}_WITH_PKGCONFIG_SUPPORT)
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/support/${PROJECT_NAME}.pc.in"
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc"
@ONLY)
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc"
DESTINATION "${${PROJECT_NAME}_INSTALL_PKGCONFIGDIR}"
COMPONENT ${PROJECT_NAME}_Development)
endif()
endif()
if(${PROJECT_NAME}_WITH_STANDARD_DOCUMENTS)
install(FILES "${CMAKE_CURRENT_SOURCE_DIR}/AUTHORS"
"${CMAKE_CURRENT_SOURCE_DIR}/COPYING"
"${CMAKE_CURRENT_SOURCE_DIR}/COPYING.LESSER"
"${CMAKE_CURRENT_SOURCE_DIR}/HISTORY"
"${CMAKE_CURRENT_SOURCE_DIR}/README"
"${CMAKE_CURRENT_SOURCE_DIR}/THANKS"
DESTINATION "${CMAKE_INSTALL_DOCDIR}"
COMPONENT ${PROJECT_NAME}_Runtime)
endif()
if(${PROJECT_NAME}_WITH_HTML_DOCUMENTATION OR ${PROJECT_NAME}_WITH_PDF_DOCUMENTATION)
add_subdirectory(documentation)
endif()
if(${PROJECT_NAME}_WITH_STEP_TESTING_TOOL)
find_package(cJSON REQUIRED)
find_package(Z80InsnClock REQUIRED)
add_executable(step-test-${PROJECT_NAME} "${CMAKE_CURRENT_SOURCE_DIR}/sources/step-test-Z80.c")
target_link_libraries(step-test-${PROJECT_NAME} PRIVATE ${PROJECT_NAME} cjson Z80InsnClock)
target_compile_definitions(
step-test-${PROJECT_NAME} PRIVATE
$<$<BOOL:${${PROJECT_NAME}_WITH_EXECUTE}>:STEP_TEST_Z80_WITH_EXECUTE>)
install(TARGETS step-test-${PROJECT_NAME}
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
COMPONENT ${PROJECT_NAME}_Testing
EXCLUDE_FROM_ALL)
endif()
if(${PROJECT_NAME}_WITH_TESTING_TOOL)
include(CTest)
find_package(libzip QUIET)
find_package(ZLIB QUIET)
add_executable(test-${PROJECT_NAME} "${CMAKE_CURRENT_SOURCE_DIR}/sources/test-Z80.c")
target_link_libraries(test-${PROJECT_NAME} PRIVATE ${PROJECT_NAME})
if(ZLIB_FOUND AND libzip_FOUND)
target_link_libraries(test-${PROJECT_NAME} PRIVATE ZLIB::ZLIB libzip::zip)
target_compile_definitions(test-${PROJECT_NAME} PRIVATE TEST_Z80_WITH_ARCHIVE_EXTRACTION)
endif()
if(${PROJECT_NAME}_WITH_EXECUTE)
target_compile_definitions(test-${PROJECT_NAME} PRIVATE TEST_Z80_WITH_EXECUTE)
endif()
install(TARGETS test-${PROJECT_NAME}
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
COMPONENT ${PROJECT_NAME}_Testing
EXCLUDE_FROM_ALL)
if(${PROJECT_NAME}_FETCH_TEST_FILES)
function(_fetch_files _list_path _location _destination_dir)
file(STRINGS "${_list_path}" _lines)
if(_location MATCHES ".*://.*")
set(_message_action "Downloading")
else()
set(_message_action "Copying")
get_filename_component(_location "${_location}" ABSOLUTE)
set(_location "file://${_location}")
endif()
foreach(_line ${_lines})
string(STRIP "${_line}" _line)
string(SUBSTRING "${_line}" 0 128 _file_hash)
string(SUBSTRING "${_line}" 130 -1 _file_path)
get_filename_component(_file_name "${_file_path}" NAME)
set(_file_url "${_location}/${_file_path}")
string(REPLACE " " "%20" _file_url "${_file_url}")
string(REPLACE "!" "%21" _file_url "${_file_url}")
string(REPLACE "(" "%28" _file_url "${_file_url}")
string(REPLACE ")" "%29" _file_url "${_file_url}")
string(REPLACE "," "%2C" _file_url "${_file_url}")
string(REPLACE "[" "%5B" _file_url "${_file_url}")
string(REPLACE "]" "%5D" _file_url "${_file_url}")
message(STATUS "${_message_action} \"${_file_name}\"")
file( DOWNLOAD
"${_file_url}"
"${_destination_dir}/${_file_path}"
EXPECTED_HASH SHA3_512=${_file_hash})
if( NOT "${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" VERSION_LESS 3.18 AND
(NOT ZLIB_FOUND OR NOT libzip_FOUND)
)
get_filename_component(_file_extension "${_file_name}" LAST_EXT)
if(_file_extension STREQUAL ".gz" OR _file_extension STREQUAL ".zip")
get_filename_component(_subdirectory "${_file_path}" DIRECTORY)
if(_file_extension STREQUAL ".gz")
set(_extract_pattern "*zex*.com")
else()
set(_extract_pattern "*.tap")
endif()
file( ARCHIVE_EXTRACT
INPUT "${_destination_dir}/${_file_path}"
DESTINATION "${_destination_dir}/${_subdirectory}"
PATTERNS "${_extract_pattern}"
VERBOSE)
endif()
endif()
endforeach()
endfunction()
_fetch_files(
"${CMAKE_CURRENT_SOURCE_DIR}/support/firmware.sha3-512"
"${${PROJECT_NAME}_DEPOT_LOCATION}/firmware"
"${CMAKE_CURRENT_BINARY_DIR}/depot/firmware")
_fetch_files(
"${CMAKE_CURRENT_SOURCE_DIR}/support/software.sha3-512"
"${${PROJECT_NAME}_DEPOT_LOCATION}/software"
"${CMAKE_CURRENT_BINARY_DIR}/depot/software")
if( "${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" VERSION_LESS 3.18 AND
(NOT ZLIB_FOUND OR NOT libzip_FOUND)
)
message(WARNING
"libzip or zlib could not be found on your system, which causes "
"`test-Z80` to be built without archive extraction support. "
"In this case, the build system normally extracts compressed test "
"files so that `test-Z80` can use them later, but this step has "
"failed because the version of CMake you are using is too old and "
"does not support archive extraction.\n"
"To fix this, extract all archives with the \".tar.gz\" or \".zip\" "
"extension located under "
"\"${CMAKE_CURRENT_BINARY_DIR}/depot/software/**/\".")
endif()
endif()
if(${PROJECT_NAME}_FETCH_TEST_FILES OR ${PROJECT_NAME}_DEPOT_LOCATION MATCHES ".*://.*")
set(_depot_dir "${CMAKE_CURRENT_BINARY_DIR}/depot")
else()
set(_depot_dir "${${PROJECT_NAME}_DEPOT_LOCATION}")
endif()
set(_test_name "Z80 test suites for CP/M and ZX Spectrum")
if(${PROJECT_NAME}_WITH_EXECUTE)
string(APPEND _test_name " (using `z80_execute`)")
endif()
add_test(
NAME "${_test_name}"
COMMAND test-${PROJECT_NAME}
--path "${_depot_dir}/firmware"
--path "${_depot_dir}/software/POSIX"
--path "${_depot_dir}/software/ZX Spectrum"
--all
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
unset(_test_name)
if(${PROJECT_NAME}_WITH_EXECUTE)
add_test(
NAME "Z80 test suites for CP/M and ZX Spectrum (using `z80_run`)"
COMMAND test-${PROJECT_NAME}
--run
--path "${_depot_dir}/firmware"
--path "${_depot_dir}/software/POSIX"
--path "${_depot_dir}/software/ZX Spectrum"
--all
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}")
endif()
unset(_depot_dir)
endif()
if(${PROJECT_NAME}_WITH_CODE_GENERATION_TOOLS)
add_executable(
${PROJECT_NAME}-generate-daa-af-table
"${CMAKE_CURRENT_SOURCE_DIR}/sources/generate-daa-af-table.c")
set_target_properties(
${PROJECT_NAME}-generate-daa-af-table
PROPERTIES OUTPUT_NAME generate-daa-af-table)
target_link_libraries(${PROJECT_NAME}-generate-daa-af-table PRIVATE ${PROJECT_NAME})
add_executable(
${PROJECT_NAME}-generate-pf-parity-table
"${CMAKE_CURRENT_SOURCE_DIR}/sources/generate-pf-parity-table.c")
set_target_properties(
${PROJECT_NAME}-generate-pf-parity-table
PROPERTIES OUTPUT_NAME generate-pf-parity-table)
target_link_libraries(${PROJECT_NAME}-generate-pf-parity-table PRIVATE Zeta)
endif()
if(NOT CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
execute_process(
COMMAND ${CMAKE_COMMAND} -E echo
"${PROJECT_NAME} v${PROJECT_VERSION} END")
endif()
# CMakeLists.txt EOF