| 1 |
cmake_minimum_required(VERSION 3.15) |
| 2 |
|
| 3 |
string(ASCII 27 Esc) |
| 4 |
set(ColorReset "${Esc}[m") |
| 5 |
set(ColorYellow "${Esc}[33m") |
| 6 |
set(ColorGreen "${Esc}[32m") |
| 7 |
set(ColorRed "${Esc}[31m") |
| 8 |
|
| 9 |
project(x16emu LANGUAGES C CXX) |
| 10 |
|
| 11 |
# --- Options (Replacements for Env Vars) --- |
| 12 |
option(ENABLE_LTO "Enable Link Time Optimization" ON) |
| 13 |
|
| 14 |
# Turning this off builds only the unit tests, which link no emulator core and so |
| 15 |
# need neither SDL nor a ROM. Chiefly for CI and for working on the tests. |
| 16 |
option(BUILD_EMULATOR "Build the x16emu executable and makecart" ON) |
| 17 |
|
| 18 |
# --- Configuration & Standards --- |
| 19 |
set(CMAKE_C_STANDARD 11) |
| 20 |
set(CMAKE_C_STANDARD_REQUIRED ON) |
| 21 |
set(CMAKE_CXX_STANDARD 17) |
| 22 |
set(CMAKE_CXX_STANDARD_REQUIRED ON) |
| 23 |
set(CMAKE_C_EXTENSIONS OFF) |
| 24 |
|
| 25 |
if(ENABLE_LTO) |
| 26 |
include(CheckIPOSupported) |
| 27 |
check_ipo_supported(RESULT lto_supported OUTPUT lto_error) |
| 28 |
if(lto_supported) |
| 29 |
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION ON) |
| 30 |
else() |
| 31 |
message(STATUS "[x16] LTO not supported: ${lto_error}") |
| 32 |
endif() |
| 33 |
endif() |
| 34 |
|
| 35 |
# Common compiler warnings/flags |
| 36 |
if(MSVC) |
| 37 |
# /W3 = production-level warnings, /WX = warnings as errors |
| 38 |
# Suppress common harmless warnings from the codebase: |
| 39 |
# C4244: conversion with possible loss of data (e.g., int to uint8_t) |
| 40 |
# C4267: conversion from size_t to smaller type |
| 41 |
# C4018: signed/unsigned mismatch in comparison |
| 42 |
# C4996: deprecated POSIX function names (unlink, etc.) |
| 43 |
# C4334: result of 32-bit shift implicitly converted to 64 bits |
| 44 |
# C4098: void function returning a value |
| 45 |
# C4305: truncation from double to float |
| 46 |
add_compile_options(/W3 /WX /wd4244 /wd4267 /wd4018 /wd4996 /wd4334 /wd4098 /wd4305) |
| 47 |
add_compile_definitions(_CRT_SECURE_NO_WARNINGS) |
| 48 |
else() |
| 49 |
add_compile_options(-Wall -Werror) |
| 50 |
endif() |
| 51 |
|
| 52 |
set(GIT_REV_HEADER_DIR "${CMAKE_CURRENT_BINARY_DIR}/generated") |
| 53 |
set(GIT_REV_HEADER "${GIT_REV_HEADER_DIR}/git_rev.h") |
| 54 |
file(MAKE_DIRECTORY ${GIT_REV_HEADER_DIR}) |
| 55 |
|
| 56 |
find_package(Git) |
| 57 |
|
| 58 |
configure_file( |
| 59 |
"${CMAKE_CURRENT_SOURCE_DIR}/GetGitRevision.cmake.in" |
| 60 |
"${CMAKE_CURRENT_BINARY_DIR}/GetGitRevision.cmake" |
| 61 |
@ONLY |
| 62 |
) |
| 63 |
|
| 64 |
# Create a custom target that runs EVERY build |
| 65 |
add_custom_target( |
| 66 |
update_git_rev |
| 67 |
ALL # Ensures this runs by default |
| 68 |
COMMAND ${CMAKE_COMMAND} |
| 69 |
-DCMAKE_SOURCE_DIR=${CMAKE_SOURCE_DIR} |
| 70 |
-DOUTPUT_FILE=${GIT_REV_HEADER} |
| 71 |
-P ${CMAKE_CURRENT_BINARY_DIR}/GetGitRevision.cmake |
| 72 |
BYPRODUCTS ${GIT_REV_HEADER} |
| 73 |
COMMENT "Checking Git revision..." |
| 74 |
) |
| 75 |
|
| 76 |
# --- Dependencies --- |
| 77 |
# The unit tests link no emulator core, so a tests-only build (-DBUILD_EMULATOR=OFF) |
| 78 |
# has no use for SDL or zlib and should not be blocked by their absence -- that is |
| 79 |
# what lets the tests run on a bare machine and keeps them honestly independent of |
| 80 |
# any one display backend. The exceptions are the tests whose sources reach SDL's |
| 81 |
# headers through glue.h (code_map and timing_speed); those are skipped when SDL |
| 82 |
# is absent rather than failing the build. |
| 83 |
if(EMSCRIPTEN) |
| 84 |
# Emscripten: SDL2 is a built-in port, not a package we search for. |
| 85 |
# We create a "Dummy" target that passes the compiler flags (-s USE_SDL=2) |
| 86 |
# to any target that links against it. |
| 87 |
add_library(SDL2::SDL2 INTERFACE IMPORTED) |
| 88 |
target_compile_options(SDL2::SDL2 INTERFACE "SHELL:-s USE_SDL=2") |
| 89 |
target_link_options(SDL2::SDL2 INTERFACE "SHELL:-s USE_SDL=2") |
| 90 |
|
| 91 |
set(SDL2_FOUND TRUE) |
| 92 |
|
| 93 |
# Emscripten ZLIB (Built-in port) |
| 94 |
add_library(ZLIB::ZLIB INTERFACE IMPORTED) |
| 95 |
target_compile_options(ZLIB::ZLIB INTERFACE "SHELL:-s USE_ZLIB=1") |
| 96 |
target_link_options(ZLIB::ZLIB INTERFACE "SHELL:-s USE_ZLIB=1") |
| 97 |
|
| 98 |
set(ZLIB_FOUND TRUE) |
| 99 |
else() |
| 100 |
if(BUILD_EMULATOR) |
| 101 |
find_package(SDL2 REQUIRED) |
| 102 |
find_package(ZLIB REQUIRED) |
| 103 |
else() |
| 104 |
find_package(SDL2 QUIET) |
| 105 |
find_package(ZLIB QUIET) |
| 106 |
endif() |
| 107 |
find_package(cJSON CONFIG QUIET) |
| 108 |
endif() |
| 109 |
|
| 110 |
find_package(Python3 COMPONENTS Interpreter REQUIRED) |
| 111 |
find_package(PkgConfig QUIET) |
| 112 |
|
| 113 |
# Dear ImGui debugger |
| 114 |
# |
| 115 |
# An in-process debugger UI in its own window: memory, disassembly, CPU, VERA, |
| 116 |
# source, breakpoints, symbols and call stack. Opt in at runtime with -imgui. |
| 117 |
# AUTO builds it when the vendored sources are present, which they are in-tree; |
| 118 |
# OFF drops the third-party C++ from the build for anyone who does not want it. |
| 119 |
|
| 120 |
set(ENABLE_IMGUI "AUTO" CACHE STRING "Build the Dear ImGui debugger UI (ON/OFF/AUTO)") |
| 121 |
set_property(CACHE ENABLE_IMGUI PROPERTY STRINGS ON OFF AUTO) |
| 122 |
|
| 123 |
set(USE_IMGUI FALSE) |
| 124 |
# imgui_impl_sdlrenderer2 needs SDL_RenderGeometry(), added in SDL 2.0.17. Some |
| 125 |
# distributions still ship older SDL2 (Raspbian bullseye, Debian oldstable), so |
| 126 |
# AUTO has to check rather than assume. find_package sets SDL2_VERSION in config |
| 127 |
# mode; fall back to pkg-config, and treat "unknown" as too old rather than |
| 128 |
# assume the best -- an unbuildable configuration is worse than a missing panel. |
| 129 |
set(IMGUI_MIN_SDL_VERSION 2.0.17) |
| 130 |
set(IMGUI_SDL_VERSION "${SDL2_VERSION}") |
| 131 |
if(NOT IMGUI_SDL_VERSION AND PKG_CONFIG_FOUND) |
| 132 |
pkg_check_modules(IMGUI_PC_SDL2 QUIET sdl2) |
| 133 |
set(IMGUI_SDL_VERSION "${IMGUI_PC_SDL2_VERSION}") |
| 134 |
endif() |
| 135 |
|
| 136 |
if(ENABLE_IMGUI STREQUAL "OFF") |
| 137 |
message(STATUS "[x16] ImGui debugger explicitly disabled.") |
| 138 |
elseif(EMSCRIPTEN) |
| 139 |
# SDL2's emscripten backend is single-window -- it renders to the one HTML |
| 140 |
# canvas -- so the second SDL_CreateWindow the debugger needs cannot |
| 141 |
# succeed. Forced off rather than left to fail at runtime, which also keeps |
| 142 |
# ~70k lines of dead C++ out of the .wasm download. |
| 143 |
if(ENABLE_IMGUI STREQUAL "ON") |
| 144 |
message(FATAL_ERROR "[x16] ENABLE_IMGUI=ON is not supported under Emscripten (single-window backend).") |
| 145 |
endif() |
| 146 |
message(STATUS "[x16] ImGui debugger disabled: unsupported under Emscripten.") |
| 147 |
elseif(NOT IMGUI_SDL_VERSION OR IMGUI_SDL_VERSION VERSION_LESS IMGUI_MIN_SDL_VERSION) |
| 148 |
if(ENABLE_IMGUI STREQUAL "ON") |
| 149 |
message(FATAL_ERROR "[x16] ENABLE_IMGUI=ON needs SDL ${IMGUI_MIN_SDL_VERSION} or newer, found '${IMGUI_SDL_VERSION}'.") |
| 150 |
endif() |
| 151 |
message(STATUS "[x16] ImGui debugger disabled: SDL '${IMGUI_SDL_VERSION}' is older than ${IMGUI_MIN_SDL_VERSION} (SDL_RenderGeometry).") |
| 152 |
elseif(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/src/extern/imgui/imgui.cpp") |
| 153 |
set(USE_IMGUI TRUE) |
| 154 |
message(STATUS "[x16] ImGui debugger enabled (SDL ${IMGUI_SDL_VERSION}).") |
| 155 |
elseif(ENABLE_IMGUI STREQUAL "ON") |
| 156 |
message(FATAL_ERROR "[x16] ENABLE_IMGUI=ON but src/extern/imgui is missing.") |
| 157 |
else() |
| 158 |
message(STATUS "[x16] Vendored ImGui not found; building without the debugger UI.") |
| 159 |
endif() |
| 160 |
|
| 161 |
# Debug Adapter Protocol server |
| 162 |
# |
| 163 |
# Speaks DAP over a TCP socket so an editor can drive the emulator's debugger. |
| 164 |
# Needs cJSON. AUTO builds it when cJSON is present and quietly leaves it out |
| 165 |
# when it is not, so a checkout without the dependency still builds an emulator |
| 166 |
# -- just one that rejects -dap. ON makes a missing cJSON an error instead. |
| 167 |
|
| 168 |
set(ENABLE_DAP "AUTO" CACHE STRING "Enable the Debug Adapter Protocol server (ON/OFF/AUTO)") |
| 169 |
set_property(CACHE ENABLE_DAP PROPERTY STRINGS ON OFF AUTO) |
| 170 |
|
| 171 |
set(USE_DAP FALSE) |
| 172 |
if(ENABLE_DAP STREQUAL "OFF") |
| 173 |
message(STATUS "[x16] DAP server explicitly disabled.") |
| 174 |
elseif(TARGET cjson OR TARGET cjson::cjson OR cJSON_FOUND) |
| 175 |
set(USE_DAP TRUE) |
| 176 |
elseif(ENABLE_DAP STREQUAL "ON") |
| 177 |
message(FATAL_ERROR "[x16] ENABLE_DAP=ON but cJSON was not found.") |
| 178 |
else() |
| 179 |
message(STATUS "[x16] cJSON not found; building without the DAP server.") |
| 180 |
endif() |
| 181 |
|
| 182 |
# Fluidsynth |
| 183 |
|
| 184 |
set(ENABLE_FLUIDSYNTH "AUTO" CACHE STRING "Enable FluidSynth MIDI support (ON/OFF/AUTO)") |
| 185 |
set_property(CACHE ENABLE_FLUIDSYNTH PROPERTY STRINGS ON OFF AUTO) |
| 186 |
|
| 187 |
set(USE_FLUIDSYNTH FALSE) |
| 188 |
|
| 189 |
if(ENABLE_FLUIDSYNTH STREQUAL "OFF") |
| 190 |
message(STATUS "[x16] FluidSynth support explicitly disabled.") |
| 191 |
elseif(EMSCRIPTEN) |
| 192 |
if (ENABLE_FLUIDSYNTH STREQUAL "ON") |
| 193 |
message(FATAL_ERROR "[x16] FluidSynth cannot be enabled for wasm builds.") |
| 194 |
elseif (ENABLE_FLUIDSYNTH STREQUAL "AUTO") |
| 195 |
message(STATUS "[x16] FluidSynth disabled for wasm builds.") |
| 196 |
endif() |
| 197 |
else() |
| 198 |
# Try pkg-config first, then fall back to find_package (for vcpkg/MSVC) |
| 199 |
if(PKG_CONFIG_FOUND) |
| 200 |
if(ENABLE_FLUIDSYNTH STREQUAL "ON") |
| 201 |
pkg_check_modules(FLUIDSYNTH REQUIRED IMPORTED_TARGET fluidsynth>=2.0) |
| 202 |
set(USE_FLUIDSYNTH TRUE) |
| 203 |
message(STATUS "[x16] FluidSynth found and enabled.") |
| 204 |
else() |
| 205 |
pkg_check_modules(FLUIDSYNTH IMPORTED_TARGET fluidsynth>=2.0) |
| 206 |
if(FLUIDSYNTH_FOUND) |
| 207 |
set(USE_FLUIDSYNTH TRUE) |
| 208 |
message(STATUS "[x16] FluidSynth found and enabled (auto).") |
| 209 |
else() |
| 210 |
message(WARNING "[x16] FluidSynth not found. MIDI support disabled (auto).") |
| 211 |
endif() |
| 212 |
endif() |
| 213 |
else() |
| 214 |
# Fallback: try find_package (works with vcpkg and system installs) |
| 215 |
find_package(FluidSynth CONFIG QUIET) |
| 216 |
if(FluidSynth_FOUND OR FLUIDSYNTH_FOUND) |
| 217 |
set(USE_FLUIDSYNTH TRUE) |
| 218 |
message(STATUS "[x16] FluidSynth found via find_package and enabled.") |
| 219 |
elseif(ENABLE_FLUIDSYNTH STREQUAL "ON") |
| 220 |
message(FATAL_ERROR "FluidSynth requested (ON), but neither pkg-config nor find_package found it.") |
| 221 |
else() |
| 222 |
message(WARNING "[x16] pkg-config missing and find_package didn't find FluidSynth. MIDI support disabled.") |
| 223 |
endif() |
| 224 |
endif() |
| 225 |
endif() |
| 226 |
|
| 227 |
# Trace Logging |
| 228 |
|
| 229 |
set(ENABLE_TRACE "AUTO" CACHE STRING "Enable trace logging support (ON/OFF/AUTO)") |
| 230 |
set_property(CACHE ENABLE_TRACE PROPERTY STRINGS ON OFF AUTO) |
| 231 |
|
| 232 |
set(USE_TRACE FALSE) |
| 233 |
|
| 234 |
if(ENABLE_TRACE STREQUAL "OFF") |
| 235 |
message(STATUS "[x16] Trace support explicitly disabled.") |
| 236 |
elseif(EMSCRIPTEN) |
| 237 |
if (ENABLE_TRACE STREQUAL "ON") |
| 238 |
message(FATAL_ERROR "[x16] Trace cannot be enabled for wasm builds.") |
| 239 |
elseif (ENABLE_TRACE STREQUAL "AUTO") |
| 240 |
message(STATUS "[x16] Trace disabled for wasm builds.") |
| 241 |
endif() |
| 242 |
else() |
| 243 |
if(ENABLE_TRACE STREQUAL "ON") |
| 244 |
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/src/rom_lst.h" AND |
| 245 |
EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/src/rom_labels.h") |
| 246 |
set(USE_TRACE ON) |
| 247 |
message(STATUS "[x16] Trace enabled and headers found (rom_lst.h, rom_labels.h).") |
| 248 |
else() |
| 249 |
message(FATAL_ERROR "[x16] Trace enabled but headers (rom_lst.h, rom_labels.h) not found.") |
| 250 |
endif() |
| 251 |
else() |
| 252 |
if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/src/rom_lst.h" AND |
| 253 |
EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/src/rom_labels.h") |
| 254 |
set(USE_TRACE ON) |
| 255 |
message(STATUS "[x16] Trace enabled (auto) and headers found (rom_lst.h, rom_labels.h).") |
| 256 |
else() |
| 257 |
message(STATUS "[x16] Trace disabled (auto). Headers (rom_lst.h, rom_labels.h) not found.") |
| 258 |
endif() |
| 259 |
endif() |
| 260 |
endif() |
| 261 |
|
| 262 |
# --- Code Generation (Python Script) --- |
| 263 |
# This replaces the 'cpu/tables.h' rule in the Makefile |
| 264 |
set(TABLE_GEN_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/src/cpu/buildtables.py") |
| 265 |
set(TABLE_OUTPUT_H "${CMAKE_CURRENT_SOURCE_DIR}/src/cpu/tables.h") |
| 266 |
set(MNEMONIC_OUTPUT_H "${CMAKE_CURRENT_SOURCE_DIR}/src/cpu/mnemonics.h") |
| 267 |
|
| 268 |
add_custom_command( |
| 269 |
OUTPUT ${TABLE_OUTPUT_H} ${MNEMONIC_OUTPUT_H} |
| 270 |
COMMAND "${Python3_EXECUTABLE}" "${TABLE_GEN_SCRIPT}" |
| 271 |
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/src/cpu" |
| 272 |
DEPENDS "${TABLE_GEN_SCRIPT}" "${CMAKE_CURRENT_SOURCE_DIR}/src/cpu/6502.opcodes" |
| 273 |
DEPENDS "${TABLE_GEN_SCRIPT}" "${CMAKE_CURRENT_SOURCE_DIR}/src/cpu/65c02.opcodes" |
| 274 |
DEPENDS "${TABLE_GEN_SCRIPT}" "${CMAKE_CURRENT_SOURCE_DIR}/src/cpu/65c816.opcodes" |
| 275 |
COMMENT "Generating CPU tables..." |
| 276 |
) |
| 277 |
# Create a target so the main executable can depend on it |
| 278 |
add_custom_target(gen_cpu_tables DEPENDS ${TABLE_OUTPUT_H}) |
| 279 |
|
| 280 |
# --- Sources --- |
| 281 |
set(X16_SOURCES |
| 282 |
src/cpu/fake6502.c |
| 283 |
src/memory.c |
| 284 |
src/io_trace.c |
| 285 |
src/perf_budget.c |
| 286 |
src/vera_bandwidth.c |
| 287 |
src/disasm.c |
| 288 |
src/video.c |
| 289 |
src/sprite_trace.c |
| 290 |
src/i2c.c |
| 291 |
src/smc.c |
| 292 |
src/rtc.c |
| 293 |
src/via.c |
| 294 |
src/serial.c |
| 295 |
src/ieee.c |
| 296 |
src/vera_spi.c |
| 297 |
src/audio.c |
| 298 |
src/vera_pcm.c |
| 299 |
src/vera_psg.c |
| 300 |
src/sdcard.c |
| 301 |
src/sdcard_fat.c |
| 302 |
src/main.c |
| 303 |
src/debugger.c |
| 304 |
src/dbg_info.c |
| 305 |
src/dbg_load.c |
| 306 |
src/source_view.c |
| 307 |
src/insn_info.c |
| 308 |
src/code_map.c |
| 309 |
src/debug_core.c |
| 310 |
src/cpu/irq_ctx.c |
| 311 |
src/javascript_interface.c |
| 312 |
src/joystick.c |
| 313 |
src/rendertext.c |
| 314 |
src/keyboard.c |
| 315 |
src/icon.c |
| 316 |
src/timing.c |
| 317 |
src/wav_recorder.c |
| 318 |
src/testbench.c |
| 319 |
src/files.c |
| 320 |
src/cartridge.c |
| 321 |
src/iso_8859_15.c |
| 322 |
src/ymglue.cpp |
| 323 |
src/midi.c |
| 324 |
src/extern/ymfm/src/ymfm_opm.cpp |
| 325 |
) |
| 326 |
|
| 327 |
if(USE_IMGUI) |
| 328 |
# Vendored Dear ImGui (docking branch) + the SDL2 / SDLRenderer2 backends, |
| 329 |
# kept in their own list so the project's strict warnings can be relaxed |
| 330 |
# for just these files: ImGui does not build clean under /W3 /WX or |
| 331 |
# -Wall -Werror, and it is not ours to fix. The debug_ui sources are |
| 332 |
# deliberately NOT in this list -- see the warning settings below. |
| 333 |
set(IMGUI_SOURCES |
| 334 |
src/extern/imgui/imgui.cpp |
| 335 |
src/extern/imgui/imgui_draw.cpp |
| 336 |
src/extern/imgui/imgui_tables.cpp |
| 337 |
src/extern/imgui/imgui_widgets.cpp |
| 338 |
src/extern/imgui/imgui_demo.cpp |
| 339 |
src/extern/imgui/backends/imgui_impl_sdl2.cpp |
| 340 |
src/extern/imgui/backends/imgui_impl_sdlrenderer2.cpp |
| 341 |
) |
| 342 |
|
| 343 |
# The debug_ui module: a C-callable core plus self-registering panels. |
| 344 |
# Adding a panel means dropping a file under src/debug_ui/panels/ and |
| 345 |
# listing it here. |
| 346 |
set(DEBUG_UI_SOURCES |
| 347 |
src/debug_ui/debug_ui.cpp |
| 348 |
src/debug_ui/debug_ui_panels.cpp |
| 349 |
src/debug_ui/debug_ui_settings.cpp |
| 350 |
src/debug_ui/io_reg_info.cpp |
| 351 |
src/debug_ui/panels/memory_panel.cpp |
| 352 |
src/debug_ui/panels/disasm_panel.cpp |
| 353 |
src/debug_ui/panels/cpu_panel.cpp |
| 354 |
src/debug_ui/panels/vera_panel.cpp |
| 355 |
src/debug_ui/panels/sprite_multiplex_tab.cpp |
| 356 |
src/debug_ui/panels/source_panel.cpp |
| 357 |
src/debug_ui/panels/breakpoints_panel.cpp |
| 358 |
src/debug_ui/panels/symbols_panel.cpp |
| 359 |
src/debug_ui/panels/callstack_panel.cpp |
| 360 |
src/debug_ui/panels/psg_panel.cpp |
| 361 |
src/debug_ui/panels/fm_panel.cpp |
| 362 |
src/debug_ui/panels/pcm_panel.cpp |
| 363 |
src/debug_ui/panels/io_panel.cpp |
| 364 |
src/debug_ui/panels/perf_panel.cpp |
| 365 |
) |
| 366 |
|
| 367 |
list(APPEND X16_SOURCES ${IMGUI_SOURCES} ${DEBUG_UI_SOURCES}) |
| 368 |
endif() |
| 369 |
|
| 370 |
if(WIN32) |
| 371 |
list(APPEND X16_SOURCES src/video_win32.c) |
| 372 |
endif() |
| 373 |
|
| 374 |
if(USE_DAP) |
| 375 |
list(APPEND X16_SOURCES src/debug_server.c src/perf_json.c) |
| 376 |
endif() |
| 377 |
|
| 378 |
# The Retro Remote Debug Controller's control port (-controlport): the HTTP |
| 379 |
# contract a test harness drives, served by the vendored core over |
| 380 |
# control_backend.c. /perf, its performance metrics, shares perf_json.c with |
| 381 |
# the DAP server and so comes with it (USE_DAP); without cJSON the port serves |
| 382 |
# contract 0.5. The core is POSIX: on Windows its entry points are no-ops. |
| 383 |
list(APPEND X16_SOURCES |
| 384 |
src/control_backend.c |
| 385 |
src/extern/retro-remote-debug-controller/core/retro_control.c) |
| 386 |
|
| 387 |
# --- Main Executable Target --- |
| 388 |
# Guarded so a tests-only build skips the emulator and its SDL dependency. The |
| 389 |
# body is left un-indented deliberately: CMake ignores whitespace, and |
| 390 |
# re-indenting ~150 lines would bury the one-line change in noise. |
| 391 |
if(BUILD_EMULATOR) |
| 392 |
|
| 393 |
add_executable(x16emu ${X16_SOURCES}) |
| 394 |
|
| 395 |
# Ensure the Python script runs before compiling x16emu |
| 396 |
add_dependencies(x16emu gen_cpu_tables) |
| 397 |
|
| 398 |
# Add git revision header |
| 399 |
add_dependencies(x16emu update_git_rev) |
| 400 |
|
| 401 |
# Includes |
| 402 |
target_include_directories(x16emu PRIVATE |
| 403 |
src |
| 404 |
src/extern/include |
| 405 |
src/extern/ymfm/src |
| 406 |
src/extern/retro-remote-debug-controller/core |
| 407 |
${GIT_REV_HEADER_DIR} |
| 408 |
) |
| 409 |
|
| 410 |
if(USE_IMGUI) |
| 411 |
target_include_directories(x16emu PRIVATE |
| 412 |
src/extern/imgui |
| 413 |
src/extern/imgui/backends |
| 414 |
src/extern/imgui_club |
| 415 |
src/debug_ui |
| 416 |
) |
| 417 |
target_compile_definitions(x16emu PRIVATE HAS_IMGUI) |
| 418 |
# Vendored ImGui does not build clean under this project's warning level, |
| 419 |
# and it is not ours to fix -- so warnings are silenced for those files |
| 420 |
# only. The debug_ui sources ARE ours and are held to the same standard as |
| 421 |
# the rest of the tree; suppressing them too would have hidden real defects |
| 422 |
# in the code most likely to contain them. |
| 423 |
if(MSVC) |
| 424 |
set_source_files_properties(${IMGUI_SOURCES} PROPERTIES COMPILE_OPTIONS "/w") |
| 425 |
else() |
| 426 |
set_source_files_properties(${IMGUI_SOURCES} PROPERTIES COMPILE_OPTIONS "-w") |
| 427 |
endif() |
| 428 |
endif() |
| 429 |
|
| 430 |
if(USE_TRACE) |
| 431 |
target_compile_definitions(x16emu PRIVATE TRACE) |
| 432 |
endif() |
| 433 |
|
| 434 |
# Linking |
| 435 |
target_link_libraries(x16emu PRIVATE |
| 436 |
SDL2::SDL2 |
| 437 |
ZLIB::ZLIB |
| 438 |
) |
| 439 |
|
| 440 |
if(TARGET SDL2::SDL2main) |
| 441 |
target_link_libraries(x16emu PRIVATE SDL2::SDL2main) |
| 442 |
endif() |
| 443 |
|
| 444 |
if(USE_DAP) |
| 445 |
target_compile_definitions(x16emu PRIVATE HAS_DAP) |
| 446 |
if(TARGET cjson::cjson) |
| 447 |
target_link_libraries(x16emu PRIVATE cjson::cjson) |
| 448 |
else() |
| 449 |
target_link_libraries(x16emu PRIVATE cjson) |
| 450 |
endif() |
| 451 |
if(WIN32) |
| 452 |
target_link_libraries(x16emu PRIVATE ws2_32) |
| 453 |
endif() |
| 454 |
endif() |
| 455 |
|
| 456 |
if(USE_FLUIDSYNTH) |
| 457 |
add_compile_definitions(HAS_FLUIDSYNTH) |
| 458 |
if(TARGET PkgConfig::FLUIDSYNTH) |
| 459 |
target_link_libraries(x16emu PRIVATE PkgConfig::FLUIDSYNTH) |
| 460 |
elseif(TARGET FluidSynth::libfluidsynth) |
| 461 |
target_link_libraries(x16emu PRIVATE FluidSynth::libfluidsynth) |
| 462 |
elseif(FLUIDSYNTH_LIBRARIES) |
| 463 |
target_link_libraries(x16emu PRIVATE ${FLUIDSYNTH_LIBRARIES}) |
| 464 |
target_include_directories(x16emu PRIVATE ${FLUIDSYNTH_INCLUDE_DIRS}) |
| 465 |
endif() |
| 466 |
endif() |
| 467 |
|
| 468 |
# Windows Specifics |
| 469 |
if(WIN32) |
| 470 |
# MinGW Linker flags |
| 471 |
if(MINGW) |
| 472 |
target_link_options(x16emu PRIVATE |
| 473 |
-static-libstdc++ |
| 474 |
-static-libgcc |
| 475 |
-Wl,--subsystem,console |
| 476 |
) |
| 477 |
endif() |
| 478 |
if(MSVC) |
| 479 |
target_link_options(x16emu PRIVATE /SUBSYSTEM:CONSOLE) |
| 480 |
endif() |
| 481 |
target_link_libraries(x16emu PRIVATE dwmapi) |
| 482 |
endif() |
| 483 |
|
| 484 |
# macOS Specifics |
| 485 |
if(APPLE) |
| 486 |
|
| 487 |
find_library(COREAUDIO CoreAudio REQUIRED) |
| 488 |
find_library(AUDIOTOOLBOX AudioToolbox REQUIRED) |
| 489 |
find_library(FORCEFEEDBACK ForceFeedback REQUIRED) |
| 490 |
find_library(COREVIDEO CoreVideo REQUIRED) |
| 491 |
find_library(COCOA Cocoa REQUIRED) |
| 492 |
find_library(CARBON Carbon REQUIRED) |
| 493 |
find_library(IOKIT IOKit REQUIRED) |
| 494 |
find_library(ICONV iconv REQUIRED) |
| 495 |
find_library(QUARTZCORE QuartzCore REQUIRED) |
| 496 |
find_library(METAL Metal REQUIRED) |
| 497 |
find_library(COREHAPTICS CoreHaptics REQUIRED) |
| 498 |
find_library(GAMECONTROLLER GameController REQUIRED) |
| 499 |
|
| 500 |
target_link_libraries(x16emu PRIVATE |
| 501 |
${COREAUDIO} ${AUDIOTOOLBOX} ${FORCEFEEDBACK} |
| 502 |
${COREVIDEO} ${COCOA} ${CARBON} ${IOKIT} ${ICONV} |
| 503 |
${QUARTZCORE} ${METAL} ${COREHAPTICS} ${GAMECONTROLLER} |
| 504 |
) |
| 505 |
endif() |
| 506 |
|
| 507 |
# Linux/Default Specifics |
| 508 |
if(UNIX AND NOT APPLE AND NOT EMSCRIPTEN) |
| 509 |
target_link_libraries(x16emu PRIVATE dl pthread m) |
| 510 |
endif() |
| 511 |
|
| 512 |
# Emscripten |
| 513 |
if(EMSCRIPTEN) |
| 514 |
set_target_properties(x16emu PROPERTIES SUFFIX ".html") |
| 515 |
target_link_options(x16emu PRIVATE |
| 516 |
--shell-file ${CMAKE_CURRENT_SOURCE_DIR}/webassembly/x16emu-template.html |
| 517 |
--preload-file ${CMAKE_CURRENT_SOURCE_DIR}/build/rom.bin |
| 518 |
"SHELL:-s TOTAL_MEMORY=32MB" |
| 519 |
"SHELL:-s ASSERTIONS=1" |
| 520 |
"SHELL:-s DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR=1" |
| 521 |
"SHELL:-s EXPORTED_FUNCTIONS=['_j2c_reset','_j2c_paste','_j2c_start_audio','_main']" |
| 522 |
"SHELL:-s EXPORTED_RUNTIME_METHODS=['ccall','cwrap']" |
| 523 |
"SHELL:-s USE_ZLIB=1" |
| 524 |
"SHELL:-s EXIT_RUNTIME=1" |
| 525 |
) |
| 526 |
endif() |
| 527 |
|
| 528 |
# --- Secondary Target: Makecart --- |
| 529 |
add_executable(makecart |
| 530 |
src/makecart.c |
| 531 |
src/files.c |
| 532 |
src/cartridge.c |
| 533 |
src/makecart_javascript_interface.c |
| 534 |
) |
| 535 |
|
| 536 |
add_dependencies(makecart update_git_rev) |
| 537 |
|
| 538 |
# Makecart dependencies |
| 539 |
target_include_directories(makecart PRIVATE |
| 540 |
src |
| 541 |
src/extern/include |
| 542 |
${GIT_REV_HEADER_DIR} |
| 543 |
) |
| 544 |
target_link_libraries(makecart PRIVATE |
| 545 |
ZLIB::ZLIB |
| 546 |
SDL2::SDL2 |
| 547 |
) |
| 548 |
|
| 549 |
if(TARGET SDL2::SDL2main) |
| 550 |
target_link_libraries(makecart PRIVATE SDL2::SDL2main) |
| 551 |
endif() |
| 552 |
|
| 553 |
if(EMSCRIPTEN) |
| 554 |
set_target_properties(makecart PROPERTIES SUFFIX ".html") |
| 555 |
target_link_options(makecart PRIVATE "SHELL:-s USE_ZLIB=1") |
| 556 |
endif() |
| 557 |
|
| 558 |
endif() # BUILD_EMULATOR |
| 559 |
|
| 560 |
# --- Optional: unit tests --- |
| 561 |
# Every test is off by default so none of them affect the normal `x16emu` build. |
| 562 |
# -DBUILD_TESTS=ON turns the lot on at once, which is what CI does; the per-test |
| 563 |
# options remain for building a single one while working on it. Each test stubs |
| 564 |
# out whatever it needs from the emulator core, so none of them link x16emu, and |
| 565 |
# none of them need a ROM. |
| 566 |
# |
| 567 |
# Emscripten is excluded throughout: the output there is .js/.wasm, which ctest |
| 568 |
# cannot execute as a plain binary. |
| 569 |
option(BUILD_TESTS "Build every unit test" OFF) |
| 570 |
|
| 571 |
# add_test() only writes a CTestTestfile when testing is enabled, so this has to |
| 572 |
# come before the x16_add_test() calls below. |
| 573 |
if(NOT EMSCRIPTEN) |
| 574 |
enable_testing() |
| 575 |
endif() |
| 576 |
|
| 577 |
# Everything x16_add_test() registers hangs off this, so CI can build the whole |
| 578 |
# suite by name without naming each test -- and without a bare --build, which |
| 579 |
# would drag in the emulator and duplicate what the platform jobs already report. |
| 580 |
# Without it, "adding a test is one line" would be false: the workflow would be |
| 581 |
# a second place to remember, and forgetting it leaves ctest running executables |
| 582 |
# that were never compiled. |
| 583 |
add_custom_target(unit_tests) |
| 584 |
|
| 585 |
# x16_add_test(<name> SOURCES <src>... [NEEDS_SDL] [NEEDS_CPU_TABLES]) |
| 586 |
# |
| 587 |
# Declares the per-test BUILD_<NAME>_TEST option, builds tests/<name>_test from |
| 588 |
# SOURCES, and registers it with ctest. Adding a test is therefore one line in |
| 589 |
# one place, which matters when many tests land in parallel: a shared block per |
| 590 |
# test would make this file a standing merge conflict. |
| 591 |
# |
| 592 |
# NEEDS_SDL marks a test whose sources reach SDL's headers (via glue.h). Those |
| 593 |
# are skipped rather than failing the build when SDL is absent, so the tests that |
| 594 |
# genuinely stand alone still run on a machine without it. |
| 595 |
function(x16_add_test name) |
| 596 |
cmake_parse_arguments(T "NEEDS_SDL;NEEDS_CPU_TABLES" "" "SOURCES" ${ARGN}) |
| 597 |
|
| 598 |
string(TOUPPER "${name}" name_uc) |
| 599 |
option(BUILD_${name_uc}_TEST "Build the ${name} unit test" OFF) |
| 600 |
|
| 601 |
if(EMSCRIPTEN) |
| 602 |
return() |
| 603 |
endif() |
| 604 |
if(NOT BUILD_TESTS AND NOT BUILD_${name_uc}_TEST) |
| 605 |
return() |
| 606 |
endif() |
| 607 |
if(T_NEEDS_SDL AND NOT SDL2_FOUND) |
| 608 |
message(STATUS "SDL2 not found: skipping ${name} test") |
| 609 |
return() |
| 610 |
endif() |
| 611 |
|
| 612 |
add_executable(${name}_test ${T_SOURCES}) |
| 613 |
target_include_directories(${name}_test PRIVATE src) |
| 614 |
if(T_NEEDS_SDL) |
| 615 |
target_include_directories(${name}_test PRIVATE ${SDL2_INCLUDE_DIRS}) |
| 616 |
endif() |
| 617 |
if(T_NEEDS_CPU_TABLES) |
| 618 |
add_dependencies(${name}_test gen_cpu_tables) |
| 619 |
endif() |
| 620 |
add_dependencies(unit_tests ${name}_test) |
| 621 |
add_test(NAME ${name} COMMAND ${name}_test) |
| 622 |
endfunction() |
| 623 |
|
| 624 |
# dbg_info.c has no dependency on the emulator core, so this links it on its own. |
| 625 |
x16_add_test(dbg_info |
| 626 |
SOURCES tests/test_dbg_info.c src/dbg_info.c) |
| 627 |
|
| 628 |
# code_map.c leans on only disasm(), dbg_info and two core symbols, so the test |
| 629 |
# supplies its own memory and register file rather than linking the emulator |
| 630 |
# core. disasm.c still includes SDL headers, and the generated cpu/mnemonics.h. |
| 631 |
x16_add_test(code_map NEEDS_SDL NEEDS_CPU_TABLES |
| 632 |
SOURCES tests/test_code_map.c src/code_map.c src/disasm.c src/dbg_info.c) |
| 633 |
|
| 634 |
# debug_core.c reaches for only the register file, the bank registers and a debug |
| 635 |
# memory read, so the test supplies its own and links no emulator core. |
| 636 |
x16_add_test(debug_core |
| 637 |
SOURCES tests/test_debug_core.c src/debug_core.c) |
| 638 |
|
| 639 |
# The speed arithmetic in timing.c depends only on the machine's configured |
| 640 |
# clock, so the test supplies the few emulator globals it touches. |
| 641 |
x16_add_test(timing_speed NEEDS_SDL |
| 642 |
SOURCES tests/test_timing_speed.c src/timing.c) |
| 643 |
|
| 644 |
# irq_ctx.c is pure bookkeeping with no dependencies, so the test links it alone. |
| 645 |
x16_add_test(irq_ctx |
| 646 |
SOURCES tests/test_irq_ctx.c src/cpu/irq_ctx.c) |
| 647 |
|
| 648 |
# dbg_load.c reports loads to dbg_info and source_view, so the test links those |
| 649 |
# two alongside it. dbg_info.c has no dependency on the emulator core either. |
| 650 |
x16_add_test(dbg_load |
| 651 |
SOURCES tests/test_dbg_load.c src/dbg_load.c src/dbg_info.c src/source_view.c) |
| 652 |
|
| 653 |
# vera_pcm.c includes only its own header and libc, so the test links it alone. |
| 654 |
x16_add_test(vera_pcm |
| 655 |
SOURCES tests/test_vera_pcm.c tests/support/harness.c src/vera_pcm.c) |
| 656 |
|
| 657 |
# io_trace.c is deliberately free of emulator dependencies -- memory.c calls it, |
| 658 |
# and memory.c is linked into tests that pair it with fake devices -- so the |
| 659 |
# test links it alone, with no CPU, no memory and no SDL. |
| 660 |
x16_add_test(io_trace |
| 661 |
SOURCES tests/test_io_trace.c tests/support/harness.c src/io_trace.c) |
| 662 |
|
| 663 |
# sprite_trace.c is fed scalars by video.c rather than reaching into it, which is |
| 664 |
# what lets the multiplexing analysis -- generation lifetimes, effective versus |
| 665 |
# phantom sprites, budget overrun, burst costing -- be driven directly here |
| 666 |
# without standing up a VERA. |
| 667 |
x16_add_test(sprite_trace |
| 668 |
SOURCES tests/test_sprite_trace.c tests/support/harness.c src/sprite_trace.c) |
| 669 |
|
| 670 |
# perf_budget.c takes everything it knows about the machine as an argument, for |
| 671 |
# exactly this reason: the cycle classification and the statistics on top of it |
| 672 |
# can be driven directly, with no CPU to run, no video to raise a frame and no |
| 673 |
# SDL to link. |
| 674 |
x16_add_test(perf_budget |
| 675 |
SOURCES tests/test_perf_budget.c tests/support/harness.c src/perf_budget.c) |
| 676 |
|
| 677 |
# vera_bandwidth.c is the same shape as perf_budget.c and for the same reason: |
| 678 |
# it takes a layer's mode as five scalars rather than video.c's property struct, |
| 679 |
# so VERA's fetch arithmetic -- which is where every bandwidth figure comes from |
| 680 |
# -- can be checked against the RTL's decode tables with nothing else standing. |
| 681 |
x16_add_test(vera_bandwidth |
| 682 |
SOURCES tests/test_vera_bandwidth.c tests/support/harness.c src/vera_bandwidth.c) |
| 683 |
|
| 684 |
# The FAT index parses untrusted binary data, so the test builds synthetic FAT16 |
| 685 |
# and FAT32 images and reads them back. It stubs the five file-access functions |
| 686 |
# onto stdio rather than linking src/files.c, which would drag in SDL and zlib |
| 687 |
# to test nothing extra: what is under test is the parser. |
| 688 |
x16_add_test(sdcard_fat |
| 689 |
SOURCES tests/test_sdcard_fat.c tests/support/harness.c src/sdcard_fat.c) |
| 690 |
|
| 691 |
# vera_psg.c likewise has no dependency beyond its own header and libc. |
| 692 |
x16_add_test(vera_psg |
| 693 |
SOURCES tests/test_vera_psg.c tests/support/harness.c src/vera_psg.c) |
| 694 |
|
| 695 |
# The real video.c, which is VERA plus the SDL host in one file. The fixture |
| 696 |
# supplies the host half so the emulation half can be driven directly; the audio |
| 697 |
# modules are linked for real because video.c routes $9F3B-$9F3D into them and |
| 698 |
# they have no dependencies of their own. |
| 699 |
x16_add_test(vera_video NEEDS_SDL |
| 700 |
SOURCES tests/test_vera_video.c tests/support/video_fixture.c tests/support/harness.c |
| 701 |
src/video.c src/sprite_trace.c src/vera_bandwidth.c src/vera_pcm.c src/vera_psg.c src/vera_spi.c) |
| 702 |
|
| 703 |
# Sprite multiplexing end to end: attributes rewritten part-way down a frame, |
| 704 |
# measured through the real renderer rather than through the recorder's API. |
| 705 |
x16_add_test(sprite_multiplex NEEDS_SDL |
| 706 |
SOURCES tests/test_sprite_multiplex.c tests/support/video_fixture.c tests/support/harness.c |
| 707 |
src/video.c src/sprite_trace.c src/vera_bandwidth.c src/vera_pcm.c src/vera_psg.c src/vera_spi.c) |
| 708 |
|
| 709 |
if(TARGET sprite_multiplex_test) |
| 710 |
target_include_directories(sprite_multiplex_test PRIVATE src src/extern/include) |
| 711 |
if(TARGET SDL2::SDL2) |
| 712 |
target_link_libraries(sprite_multiplex_test PRIVATE SDL2::SDL2) |
| 713 |
endif() |
| 714 |
if(UNIX AND NOT APPLE) |
| 715 |
target_link_libraries(sprite_multiplex_test PRIVATE m) |
| 716 |
endif() |
| 717 |
endif() |
| 718 |
|
| 719 |
# video.c includes gif.h, which is vendored rather than sitting alongside it. |
| 720 |
# It also calls SDL directly from its host half, so unlike the other NEEDS_SDL |
| 721 |
# tests -- which only need the headers -- this one links the library too. |
| 722 |
if(TARGET vera_video_test) |
| 723 |
target_include_directories(vera_video_test PRIVATE src/extern/include) |
| 724 |
if(TARGET SDL2::SDL2) |
| 725 |
target_link_libraries(vera_video_test PRIVATE SDL2::SDL2) |
| 726 |
endif() |
| 727 |
# video.c calls round(). The emulator picks libm up transitively from its |
| 728 |
# other dependencies; this target links fewer of them, so it asks directly. |
| 729 |
if(UNIX AND NOT APPLE) |
| 730 |
target_link_libraries(vera_video_test PRIVATE m) |
| 731 |
endif() |
| 732 |
endif() |
| 733 |
|
| 734 |
# The CPU core reaches outside itself for only six symbols, all supplied by the |
| 735 |
# fixture, so this links the real instruction tables against a flat 64K memory |
| 736 |
# and nothing else. irq_ctx.c comes along because fake6502.c reports interrupt |
| 737 |
# entry and exit to it. |
| 738 |
x16_add_test(cpu_smoke NEEDS_CPU_TABLES |
| 739 |
SOURCES tests/test_cpu_smoke.c tests/support/cpu_fixture.c tests/support/harness.c |
| 740 |
src/cpu/fake6502.c src/cpu/irq_ctx.c) |
| 741 |
|
| 742 |
x16_add_test(cpu_loadstore NEEDS_CPU_TABLES |
| 743 |
SOURCES tests/test_cpu_loadstore.c tests/support/cpu_fixture.c tests/support/harness.c |
| 744 |
src/cpu/fake6502.c src/cpu/irq_ctx.c) |
| 745 |
|
| 746 |
x16_add_test(cpu_adc_sbc NEEDS_CPU_TABLES |
| 747 |
SOURCES tests/test_cpu_adc_sbc.c tests/support/cpu_fixture.c tests/support/harness.c |
| 748 |
src/cpu/fake6502.c src/cpu/irq_ctx.c) |
| 749 |
|
| 750 |
x16_add_test(cpu_decimal NEEDS_CPU_TABLES |
| 751 |
SOURCES tests/test_cpu_decimal.c tests/support/cpu_fixture.c tests/support/harness.c |
| 752 |
src/cpu/fake6502.c src/cpu/irq_ctx.c) |
| 753 |
|
| 754 |
x16_add_test(cpu_steprun NEEDS_CPU_TABLES |
| 755 |
SOURCES tests/test_cpu_steprun.c tests/support/cpu_fixture.c tests/support/harness.c |
| 756 |
src/cpu/fake6502.c src/cpu/irq_ctx.c) |
| 757 |
|
| 758 |
# Klaus Dormann's functional tests: a program that walks every opcode and |
| 759 |
# checks its own results. The binaries are fetched, not committed, and the test |
| 760 |
# reports skipped without them. |
| 761 |
x16_add_test(klaus NEEDS_CPU_TABLES |
| 762 |
SOURCES tests/test_klaus.c tests/support/cpu_fixture.c tests/support/harness.c |
| 763 |
src/cpu/fake6502.c src/cpu/irq_ctx.c) |
| 764 |
|
| 765 |
# SingleStepTests/ProcessorTests: every opcode, thousands of randomised states |
| 766 |
# each. Fixtures are fetched by tests/fetch_pt.py and not committed. |
| 767 |
x16_add_test(processor_tests NEEDS_CPU_TABLES |
| 768 |
SOURCES tests/test_processor_tests.c tests/support/cpu_fixture.c |
| 769 |
tests/support/harness.c src/cpu/fake6502.c src/cpu/irq_ctx.c) |
| 770 |
|
| 771 |
# The same binary over the 65816 suites. One executable rather than three: the |
| 772 |
# fixtures differ only in which cases they hold, and each case says which core |
| 773 |
# to run it on. Registered separately so a failure names the mode. |
| 774 |
if(TARGET processor_tests_test) |
| 775 |
add_test(NAME processor_tests_816_emu |
| 776 |
COMMAND processor_tests_test 816-emu) |
| 777 |
add_test(NAME processor_tests_816_native |
| 778 |
COMMAND processor_tests_test 816-native) |
| 779 |
endif() |
| 780 |
|
| 781 |
# The generated opcode tables against the published 65C02 spec. ProcessorTests |
| 782 |
# measures what the hardware does; this checks the tables still agree with the |
| 783 |
# documentation, which is a different question and has disagreed once. |
| 784 |
add_test(NAME opcode_spec |
| 785 |
COMMAND "${Python3_EXECUTABLE}" "${CMAKE_SOURCE_DIR}/tests/check_opcode_spec.py") |
| 786 |
|
| 787 |
# The VERA tests cite Verilog by file and line, which only means anything |
| 788 |
# against one revision -- the one the emulator reports itself to be. This fails |
| 789 |
# if src/video.c and the RTL pin in tests/fetch_vera_rtl.py drift apart, so a |
| 790 |
# version bump has to be a deliberate step that re-checks the citations. |
| 791 |
add_test(NAME vera_version |
| 792 |
COMMAND "${Python3_EXECUTABLE}" "${CMAKE_SOURCE_DIR}/tests/check_vera_version.py") |
| 793 |
|
| 794 |
# VERA's palette RAM is initialised from a memory file baked into the FPGA |
| 795 |
# bitstream, so the default palette is hardware rather than a ROM convention. |
| 796 |
# Skips when the RTL has not been fetched. |
| 797 |
add_test(NAME vera_palette |
| 798 |
COMMAND "${Python3_EXECUTABLE}" "${CMAKE_SOURCE_DIR}/tests/check_vera_palette.py") |
| 799 |
|
| 800 |
# Register banking: the same addresses carry different registers per DCSEL. |
| 801 |
x16_add_test(vera_regbank NEEDS_SDL |
| 802 |
SOURCES tests/test_vera_regbank.c tests/support/video_fixture.c tests/support/harness.c |
| 803 |
src/video.c src/sprite_trace.c src/vera_bandwidth.c src/vera_pcm.c src/vera_psg.c src/vera_spi.c) |
| 804 |
|
| 805 |
if(TARGET vera_regbank_test) |
| 806 |
target_include_directories(vera_regbank_test PRIVATE src/extern/include) |
| 807 |
if(TARGET SDL2::SDL2) |
| 808 |
target_link_libraries(vera_regbank_test PRIVATE SDL2::SDL2) |
| 809 |
endif() |
| 810 |
if(UNIX AND NOT APPLE) |
| 811 |
target_link_libraries(vera_regbank_test PRIVATE m) |
| 812 |
endif() |
| 813 |
endif() |
| 814 |
|
| 815 |
# The value half of the debugOn contract: a debug read must report what a real |
| 816 |
# read would. The existing contract test drives recording fakes, so it can only |
| 817 |
# check side effects; this links the real video.c. |
| 818 |
x16_add_test(vera_debug_read NEEDS_SDL |
| 819 |
SOURCES tests/test_vera_debug_read.c tests/support/video_fixture.c tests/support/harness.c |
| 820 |
src/video.c src/sprite_trace.c src/vera_bandwidth.c src/vera_pcm.c src/vera_psg.c src/vera_spi.c) |
| 821 |
|
| 822 |
if(TARGET vera_debug_read_test) |
| 823 |
target_include_directories(vera_debug_read_test PRIVATE src/extern/include) |
| 824 |
if(TARGET SDL2::SDL2) |
| 825 |
target_link_libraries(vera_debug_read_test PRIVATE SDL2::SDL2) |
| 826 |
endif() |
| 827 |
if(UNIX AND NOT APPLE) |
| 828 |
target_link_libraries(vera_debug_read_test PRIVATE m) |
| 829 |
endif() |
| 830 |
endif() |
| 831 |
|
| 832 |
# The interrupt latch and mask: which ISR bits a write can clear, and which |
| 833 |
# IEN bits a write can store. |
| 834 |
x16_add_test(vera_irq NEEDS_SDL |
| 835 |
SOURCES tests/test_vera_irq.c tests/support/video_fixture.c tests/support/harness.c |
| 836 |
src/video.c src/sprite_trace.c src/vera_bandwidth.c src/vera_pcm.c src/vera_psg.c src/vera_spi.c) |
| 837 |
|
| 838 |
if(TARGET vera_irq_test) |
| 839 |
target_include_directories(vera_irq_test PRIVATE src/extern/include) |
| 840 |
if(TARGET SDL2::SDL2) |
| 841 |
target_link_libraries(vera_irq_test PRIVATE SDL2::SDL2) |
| 842 |
endif() |
| 843 |
if(UNIX AND NOT APPLE) |
| 844 |
target_link_libraries(vera_irq_test PRIVATE m) |
| 845 |
endif() |
| 846 |
endif() |
| 847 |
|
| 848 |
# What a reset leaves behind: derived state must not outlive the registers it |
| 849 |
# was derived from. |
| 850 |
x16_add_test(vera_reset NEEDS_SDL |
| 851 |
SOURCES tests/test_vera_reset.c tests/support/video_fixture.c tests/support/harness.c |
| 852 |
src/video.c src/sprite_trace.c src/vera_bandwidth.c src/vera_pcm.c src/vera_psg.c src/vera_spi.c) |
| 853 |
|
| 854 |
if(TARGET vera_reset_test) |
| 855 |
target_include_directories(vera_reset_test PRIVATE src/extern/include) |
| 856 |
if(TARGET SDL2::SDL2) |
| 857 |
target_link_libraries(vera_reset_test PRIVATE SDL2::SDL2) |
| 858 |
endif() |
| 859 |
if(UNIX AND NOT APPLE) |
| 860 |
target_link_libraries(vera_reset_test PRIVATE m) |
| 861 |
endif() |
| 862 |
endif() |
| 863 |
|
| 864 |
# The layer registers, and the map and tile base addresses derived from them. |
| 865 |
x16_add_test(vera_layer NEEDS_SDL |
| 866 |
SOURCES tests/test_vera_layer.c tests/support/video_fixture.c tests/support/harness.c |
| 867 |
src/video.c src/sprite_trace.c src/vera_bandwidth.c src/vera_pcm.c src/vera_psg.c src/vera_spi.c) |
| 868 |
|
| 869 |
if(TARGET vera_layer_test) |
| 870 |
target_include_directories(vera_layer_test PRIVATE src/extern/include) |
| 871 |
if(TARGET SDL2::SDL2) |
| 872 |
target_link_libraries(vera_layer_test PRIVATE SDL2::SDL2) |
| 873 |
endif() |
| 874 |
if(UNIX AND NOT APPLE) |
| 875 |
target_link_libraries(vera_layer_test PRIVATE m) |
| 876 |
endif() |
| 877 |
endif() |
| 878 |
|
| 879 |
# Which row of a layer each display line shows: the vertical half of the tile |
| 880 |
# address path. |
| 881 |
x16_add_test(vera_layer_rows NEEDS_SDL |
| 882 |
SOURCES tests/test_vera_layer_rows.c tests/support/video_fixture.c tests/support/harness.c |
| 883 |
src/video.c src/sprite_trace.c src/vera_bandwidth.c src/vera_pcm.c src/vera_psg.c src/vera_spi.c) |
| 884 |
|
| 885 |
if(TARGET vera_layer_rows_test) |
| 886 |
target_include_directories(vera_layer_rows_test PRIVATE src/extern/include) |
| 887 |
if(TARGET SDL2::SDL2) |
| 888 |
target_link_libraries(vera_layer_rows_test PRIVATE SDL2::SDL2) |
| 889 |
endif() |
| 890 |
if(UNIX AND NOT APPLE) |
| 891 |
target_link_libraries(vera_layer_rows_test PRIVATE m) |
| 892 |
endif() |
| 893 |
endif() |
| 894 |
|
| 895 |
# The 65C22's interrupt flags and enables. via.c pulls in memory.h, which |
| 896 |
# includes SDL.h, so it needs the headers -- but nothing here links SDL. |
| 897 |
x16_add_test(via_irq NEEDS_SDL |
| 898 |
SOURCES tests/test_via_irq.c tests/support/via_fixture.c tests/support/harness.c |
| 899 |
src/via.c) |
| 900 |
|
| 901 |
# The 65C22's interval timers: one-shot against free-run, and where the next |
| 902 |
# count comes from. |
| 903 |
x16_add_test(via_timers NEEDS_SDL |
| 904 |
SOURCES tests/test_via_timers.c tests/support/via_fixture.c tests/support/harness.c |
| 905 |
src/via.c) |
| 906 |
|
| 907 |
# The SNES controller ports the VIA above clocks: the latch/shift register and |
| 908 |
# the virtual joystick that drives a port with no gamepad attached. io_trace.c |
| 909 |
# comes along because the latch path reports to it, and has no dependencies of |
| 910 |
# its own. |
| 911 |
x16_add_test(joystick NEEDS_SDL |
| 912 |
SOURCES tests/test_joystick.c tests/support/harness.c |
| 913 |
src/joystick.c src/io_trace.c) |
| 914 |
|
| 915 |
# joystick.c enumerates controllers through SDL, so unlike the NEEDS_SDL tests |
| 916 |
# that only want the headers, this one links the library. The test never calls |
| 917 |
# joystick_init() -- the virtual path exists precisely so it does not have to -- |
| 918 |
# but those calls still have to resolve. |
| 919 |
if(TARGET joystick_test) |
| 920 |
if(TARGET SDL2::SDL2) |
| 921 |
target_link_libraries(joystick_test PRIVATE SDL2::SDL2) |
| 922 |
endif() |
| 923 |
endif() |
| 924 |
|
| 925 |
# memory.c routes every I/O access, and carries the debugOn flag that says |
| 926 |
# whether a read is the debugger looking or the machine running. The devices |
| 927 |
# behind it are recording fakes; memory.c, debug_core.c and the CPU core are |
| 928 |
# real, so this exercises the actual routing, watchpoint and cycle accounting. |
| 929 |
x16_add_test(debugon_contract NEEDS_SDL NEEDS_CPU_TABLES |
| 930 |
SOURCES tests/test_debugon_contract.c tests/support/fake_devices.c |
| 931 |
tests/support/harness.c |
| 932 |
src/memory.c src/debug_core.c src/cpu/fake6502.c src/cpu/irq_ctx.c |
| 933 |
src/io_trace.c src/perf_budget.c) |
| 934 |
|
| 935 |
# RAM and ROM banking: the registers at $0000 and $0001 and the windows they |
| 936 |
# steer. Same real memory.c and fake devices as the debugOn tests. |
| 937 |
x16_add_test(memory_banking NEEDS_SDL NEEDS_CPU_TABLES |
| 938 |
SOURCES tests/test_memory_banking.c tests/support/fake_devices.c |
| 939 |
tests/support/harness.c |
| 940 |
src/memory.c src/debug_core.c src/cpu/fake6502.c src/cpu/irq_ctx.c |
| 941 |
src/io_trace.c src/perf_budget.c) |
| 942 |
|
| 943 |
# The write half of the debugOn contract, which does not exist: pins what a |
| 944 |
# debugger's edit costs and disturbs, since nothing can tell it apart from a |
| 945 |
# store the program executed. |
| 946 |
x16_add_test(debug_write_path NEEDS_SDL NEEDS_CPU_TABLES |
| 947 |
SOURCES tests/test_debug_write_path.c tests/support/fake_devices.c |
| 948 |
tests/support/harness.c |
| 949 |
src/memory.c src/debug_core.c src/cpu/fake6502.c src/cpu/irq_ctx.c |
| 950 |
src/io_trace.c src/perf_budget.c) |
| 951 |
|
| 952 |
# The watchpoint hook sits on the store path, so this links the same real |
| 953 |
# memory.c, debug_core.c and CPU core as the debugOn tests, and asserts that |
| 954 |
# watching an address changes nothing except that a break is reported. |
| 955 |
x16_add_test(watchpoint_purity NEEDS_SDL NEEDS_CPU_TABLES |
| 956 |
SOURCES tests/test_watchpoint_purity.c tests/support/fake_devices.c |
| 957 |
tests/support/signature.c tests/support/harness.c |
| 958 |
src/memory.c src/debug_core.c src/cpu/fake6502.c src/cpu/irq_ctx.c |
| 959 |
src/io_trace.c src/perf_budget.c) |
| 960 |
|
| 961 |
# Build summary |
| 962 |
|
| 963 |
if(ENABLE_FLUIDSYNTH STREQUAL "AUTO" AND NOT USE_FLUIDSYNTH) |
| 964 |
set(FLUID_EN_MSG "${ColorYellow}DISABLED (Missing Dependency)${ColorReset}") |
| 965 |
elseif(USE_FLUIDSYNTH) |
| 966 |
set(FLUID_EN_MSG "${ColorGreen}ENABLED${ColorReset}") |
| 967 |
else() |
| 968 |
set(FLUID_EN_MSG "DISABLED (Explicit)") |
| 969 |
endif() |
| 970 |
|
| 971 |
if(ENABLE_TRACE STREQUAL "AUTO" AND NOT USE_TRACE) |
| 972 |
set(TRACE_EN_MSG "${ColorYellow}DISABLED (Missing ROM Headers)${ColorReset}") |
| 973 |
elseif(USE_TRACE) |
| 974 |
set(TRACE_EN_MSG "${ColorGreen}ENABLED${ColorReset}") |
| 975 |
else() |
| 976 |
set(TRACE_EN_MSG "DISABLED (Explicit)") |
| 977 |
endif() |
| 978 |
|
| 979 |
message(STATUS "\n") |
| 980 |
message(STATUS "=========================================================================") |
| 981 |
message(STATUS " x16-emulator Build Options Summary") |
| 982 |
message(STATUS "=========================================================================") |
| 983 |
message(STATUS " Fluidsynth Support : ${FLUID_EN_MSG}") |
| 984 |
message(STATUS " Trace Support : ${TRACE_EN_MSG}") |
| 985 |
message(STATUS "=========================================================================\n") |