OXYGENHUB
◆ main enhanced-x16-emulator / CMakeLists.txt
39.3 KiB · Plain Text · last changed feat: the RRDC control port (-controlport), contract 0.6: GET/POST /perf from the Performance panel's measurements, built by perf_json.c with DAP's x16/perfStats; a guest marker region named in advance; a framed guest's regions carried across the frame boundary and an interrupt after $F1 counted as work (#1) 25 days ago source blame history raw
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")