# Copyright (c) 2026 Dominic Masters # # This software is released under the MIT License. # https://opensource.org/licenses/MIT # Resolve YAUL_INSTALL_ROOT (already set by the toolchain file, but guard # in case cmake/targets/ is loaded standalone for IDE tooling). if(NOT DEFINED YAUL_INSTALL_ROOT) if(DEFINED ENV{YAUL_INSTALL_ROOT}) set(YAUL_INSTALL_ROOT "$ENV{YAUL_INSTALL_ROOT}") else() set(YAUL_INSTALL_ROOT "/opt/yaul") endif() endif() # Yaul installs headers/libs under the arch-prefix sysroot subdirectory: # ${YAUL_INSTALL_ROOT}/sh2eb-elf/include/ # ${YAUL_INSTALL_ROOT}/sh2eb-elf/lib/ # Cross-compiled zlib and libzip are installed to the same sysroot. set(_YAUL_SYSROOT "${YAUL_INSTALL_ROOT}/sh2eb-elf") set(_YAUL_BIN "${YAUL_INSTALL_ROOT}/bin") # --------------------------------------------------------------------------- # Bypass system find_package calls for libraries we cross-compile into the # sh2eb-elf sysroot and install into ${_YAUL_SYSROOT}. # --------------------------------------------------------------------------- # zlib if(NOT TARGET ZLIB::ZLIB) add_library(ZLIB::ZLIB INTERFACE IMPORTED GLOBAL) set_target_properties(ZLIB::ZLIB PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${_YAUL_SYSROOT}/include" INTERFACE_LINK_LIBRARIES "${_YAUL_SYSROOT}/lib/libz.a" ) endif() set(ZLIB_FOUND TRUE CACHE BOOL "" FORCE) set(ZLIB_INCLUDE_DIR "${_YAUL_SYSROOT}/include" CACHE PATH "" FORCE) set(ZLIB_LIBRARY "${_YAUL_SYSROOT}/lib/libz.a" CACHE FILEPATH "" FORCE) # libzip — pre-installed into the sh2eb-elf sysroot; skip Findlibzip.cmake. set(libzip_FOUND TRUE CACHE BOOL "libzip found (Saturn sysroot)" FORCE) find_path(_sat_zip_inc NAMES zip.h PATHS "${_YAUL_SYSROOT}/include" NO_DEFAULT_PATH ) if(_sat_zip_inc) target_include_directories(${DUSK_LIBRARY_TARGET_NAME} PRIVATE "${_sat_zip_inc}") endif() # --------------------------------------------------------------------------- # Compile definitions # --------------------------------------------------------------------------- target_compile_definitions(${DUSK_LIBRARY_TARGET_NAME} PUBLIC DUSK_SATURN DUSK_INPUT_GAMEPAD DUSK_PLATFORM_ENDIAN_BIG DUSK_DISPLAY_WIDTH=320 DUSK_DISPLAY_HEIGHT=224 DUSK_THREAD_NONE ) # --------------------------------------------------------------------------- # Compile options # --------------------------------------------------------------------------- target_compile_options(${DUSK_LIBRARY_TARGET_NAME} PRIVATE -m2 -mb -fno-builtin -fomit-frame-pointer -w ) # --------------------------------------------------------------------------- # Include paths # --------------------------------------------------------------------------- target_include_directories(${DUSK_LIBRARY_TARGET_NAME} PRIVATE "${_YAUL_SYSROOT}/include" "${_YAUL_SYSROOT}/include/yaul" ) # --------------------------------------------------------------------------- # Link libraries # --------------------------------------------------------------------------- target_link_directories(${DUSK_LIBRARY_TARGET_NAME} PRIVATE "${_YAUL_SYSROOT}/lib" ) target_link_libraries(${DUSK_LIBRARY_TARGET_NAME} PRIVATE # --start-group/--end-group allow circular archive references # (e.g. libyaul allocator symbols referenced by libzip / yyjson objects). -Wl,--start-group "${_YAUL_SYSROOT}/lib/libyaul.a" "${_YAUL_SYSROOT}/lib/libzip.a" "${_YAUL_SYSROOT}/lib/libz.a" # GCC soft-float / soft-divide runtime (SH-2 has no FPU or hw divider). # -lgcc is resolved by the compiler driver even with -nodefaultlibs. -lgcc -Wl,--end-group ) # Yaul linker script (Saturn SH-2 memory map) and startup objects. # Startup objects must precede all other objects so use target_link_options # (those flags appear before the object-file list in cmake's link command). target_link_options(${DUSK_BINARY_TARGET_NAME} PRIVATE "-T${_YAUL_SYSROOT}/lib/ldscripts/yaul.x" "${_YAUL_SYSROOT}/lib/crt0.o" "${_YAUL_SYSROOT}/lib/init.o" # Provide SH-2 stack top addresses required by crt0.o/cpu_dual_entries.o. # RAM region: 0x06004000 .. 0x06100000 (~1 MB). # Master stack grows down from the very top; slave CPU gets 4 KB below. "-Wl,--defsym=___master_stack=0x06100000" "-Wl,--defsym=___slave_stack=0x060FF000" ) # --------------------------------------------------------------------------- # Post-build: ELF → binary → Saturn disc image (ISO + CUE) # --------------------------------------------------------------------------- set(DUSK_SAT_BIN "${CMAKE_BINARY_DIR}/Dusk.bin") set(DUSK_SAT_IP_BIN "${CMAKE_BINARY_DIR}/IP.BIN") set(DUSK_SAT_CD_DIR "${CMAKE_BINARY_DIR}/cd") set(DUSK_SAT_AUDIO_DIR "${CMAKE_BINARY_DIR}/audio-tracks") set(DUSK_SAT_ISO "${CMAKE_BINARY_DIR}/Dusk.iso") set(DUSK_SAT_CUE "${CMAKE_BINARY_DIR}/Dusk.cue") # Step 1: ELF → flat binary (loaded into Work RAM by IP.BIN) add_custom_command(TARGET ${DUSK_BINARY_TARGET_NAME} POST_BUILD COMMAND "${_YAUL_BIN}/sh2eb-elf-objcopy" -O binary "$" "${DUSK_SAT_BIN}" COMMENT "Converting ELF → ${DUSK_SAT_BIN}" ) # Step 2: flat binary → IP.BIN (boot header with region security blobs) # make-ip writes IP.BIN into dirname(arg1), so it lands at ${CMAKE_BINARY_DIR}/IP.BIN. # Pass -1 for 1st-read-size so make-ip uses the actual file size. add_custom_command(TARGET ${DUSK_BINARY_TARGET_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E env "YAUL_INSTALL_ROOT=${YAUL_INSTALL_ROOT}" "YAUL_ARCH_SH_PREFIX=sh2eb-elf" "${_YAUL_BIN}/make-ip" "${DUSK_SAT_BIN}" "V1.000" "20260101" "JTUE" "J" "DUSK" "0x06100000" "0x060FF000" "0x06004000" "-1" COMMENT "Generating IP.BIN" ) # Step 3: build CD filesystem tree and create ISO 9660 image add_custom_command(TARGET ${DUSK_BINARY_TARGET_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E make_directory "${DUSK_SAT_CD_DIR}" COMMAND ${CMAKE_COMMAND} -E make_directory "${DUSK_SAT_AUDIO_DIR}" COMMAND ${CMAKE_COMMAND} -E copy "${DUSK_SAT_BIN}" "${DUSK_SAT_CD_DIR}/A.BIN" # ISO 9660 requires these auxiliary text files COMMAND ${CMAKE_COMMAND} -E touch "${DUSK_SAT_CD_DIR}/ABS.TXT" COMMAND ${CMAKE_COMMAND} -E touch "${DUSK_SAT_CD_DIR}/BIB.TXT" COMMAND ${CMAKE_COMMAND} -E touch "${DUSK_SAT_CD_DIR}/CPY.TXT" COMMAND ${CMAKE_COMMAND} -E env "YAUL_INSTALL_ROOT=${YAUL_INSTALL_ROOT}" "MAKE_ISO_XORRISOFS=/usr/bin/xorrisofs" "${_YAUL_BIN}/make-iso" "${DUSK_SAT_CD_DIR}" "${DUSK_SAT_IP_BIN}" "${CMAKE_BINARY_DIR}" "Dusk" COMMENT "Generating ${DUSK_SAT_ISO}" ) # Step 4: ISO → CUE sheet (rename .iso → .bin for a classic BIN/CUE pair # if desired; emulators accept .iso+.cue as-is) add_custom_command(TARGET ${DUSK_BINARY_TARGET_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E env "YAUL_INSTALL_ROOT=${YAUL_INSTALL_ROOT}" "${_YAUL_BIN}/make-cue" "${DUSK_SAT_AUDIO_DIR}" "${DUSK_SAT_ISO}" COMMENT "Generating ${DUSK_SAT_CUE}" )