# Copyright (c) 2026 Eclipse ThreadX contributors
# SPDX-License-Identifier: MIT
# Some portions generated by Claude Code (Opus 5).
#
# Example build for Cortex-R52 on the NXP S32Z280-594EVB, RTU0 core 0.
#
# Unlike the FVP example there is no automated test target here: the board is
# reached through a debug probe and a vendor GDB server, not by launching a
# model, so running an image is a manual step.  tools/read_identity.gdb loads
# an image, runs it and reports what it found.

set(EVB_DIR ${CMAKE_CURRENT_LIST_DIR})

# A bare-metal image has one flat SRAM region and no OS page permissions; access
# control belongs to the MPU, so an RWX segment is expected rather than a mistake.
# GNU ld has warned about them since binutils 2.39 and takes this flag to stay
# quiet; ld.lld does not warn and rejects the flag outright, failing the link with
# "unknown argument". Chosen by toolchain, as in the FVP example.
if(CMAKE_C_COMPILER_ID STREQUAL "GNU")
    set(EVB_LINK_QUIET_RWX -Wl,--no-warn-rwx-segments)
else()
    set(EVB_LINK_QUIET_RWX)
endif()

# Silicon M0 -- boot verification.  Deliberately does not link ThreadX: a
# failure here is then unambiguously a boot or board problem rather than a
# kernel one, which is the same reasoning as the FVP's boot_check.elf.
add_executable(s32z280_boot.elf EXCLUDE_FROM_ALL
    ${EVB_DIR}/entry.S
    ${EVB_DIR}/bsp_boot.c
    ${EVB_DIR}/linflexd.c
    ${EVB_DIR}/timer.c
    ${EVB_DIR}/gic_probe.c
    ${EVB_DIR}/mpu.c
    ${EVB_DIR}/gicv3.c
    ${EVB_DIR}/irq_dispatch.c
    ${EVB_DIR}/cache.c
        ${EVB_DIR}/tcm.c
)

target_include_directories(s32z280_boot.elf PRIVATE ${EVB_DIR})

# -g only: this image exists to be inspected through a debugger, and without
# DWARF the identity structure has no type for GDB to walk.  No effect on the
# generated code.
target_compile_options(s32z280_boot.elf PRIVATE -g)

target_link_options(s32z280_boot.elf PRIVATE
    -T${EVB_DIR}/link.lds
    -nostartfiles
    -Wl,-Map=s32z280_boot.map
    # Bare metal: one code region and one data region, with access control
    # belonging to the MPU rather than to segment permissions.
    ${EVB_LINK_QUIET_RWX}
)


# Same image as s32z280_boot.elf with the interrupt service body placed in ATCM
# instead of code RAM, so the two can be compared on the same board in the same
# session.  Separate target rather than an option so both exist at once and a
# result can be reproduced without reconfiguring.
add_executable(s32z280_atcm.elf EXCLUDE_FROM_ALL
    ${EVB_DIR}/entry.S
    ${EVB_DIR}/bsp_boot.c
    ${EVB_DIR}/linflexd.c
    ${EVB_DIR}/timer.c
    ${EVB_DIR}/gic_probe.c
    ${EVB_DIR}/mpu.c
    ${EVB_DIR}/gicv3.c
    ${EVB_DIR}/irq_dispatch.c
    ${EVB_DIR}/cache.c
        ${EVB_DIR}/tcm.c
)

target_include_directories(s32z280_atcm.elf PRIVATE ${EVB_DIR})

# -g only: this image exists to be inspected through a debugger, and without
# DWARF the identity structure has no type for GDB to walk.  No effect on the
# generated code.
target_compile_options(s32z280_atcm.elf PRIVATE -g)

target_link_options(s32z280_atcm.elf PRIVATE
    -T${EVB_DIR}/link.lds
    -nostartfiles
    -Wl,-Map=s32z280_atcm.map
    # Bare metal: one code region and one data region, with access control
    # belonging to the MPU rather than to segment permissions.
    ${EVB_LINK_QUIET_RWX}
)


target_compile_definitions(s32z280_atcm.elf PRIVATE TX_R52_ATCM_ISR)


# ThreadX demo on silicon: threads, preemption and the timer tick.  Separate
# target from s32z280_boot.elf, which deliberately does not link the kernel so
# that a boot failure there is unambiguously a board problem.
add_executable(s32z280_demo.elf EXCLUDE_FROM_ALL
    ${EVB_DIR}/entry.S
    ${EVB_DIR}/tx_initialize_low_level.S
    ${EVB_DIR}/linflexd.c
    ${EVB_DIR}/timer.c
    ${EVB_DIR}/mpu.c
    ${EVB_DIR}/gicv3.c
    ${EVB_DIR}/irq_dispatch.c
    ${EVB_DIR}/gic_probe.c
    ${EVB_DIR}/cache.c
        ${EVB_DIR}/tcm.c
    ${EVB_DIR}/thread_mpu.c
    ${EVB_DIR}/demo_s32z280.c
)

# TX_R52_USE_THREADX_IRQ routes the IRQ vector through _tx_thread_context_save
# instead of the standalone handler, and makes _tx_initialize_low_level call
# board_init().
target_compile_definitions(s32z280_demo.elf PRIVATE TX_R52_USE_THREADX_IRQ=1)
target_compile_options(s32z280_demo.elf PRIVATE -g)

target_link_libraries(s32z280_demo.elf PRIVATE threadx)

target_include_directories(s32z280_demo.elf PRIVATE
    ${EVB_DIR}
    ${CMAKE_SOURCE_DIR}/common/inc
    ${CMAKE_SOURCE_DIR}/ports/${THREADX_ARCH}/${THREADX_TOOLCHAIN}/inc
)

target_link_options(s32z280_demo.elf PRIVATE
    -T${EVB_DIR}/link.lds
    -nostartfiles
    -Wl,-Map=s32z280_demo.map
    ${EVB_LINK_QUIET_RWX}
)

# Lazy VFP context save and restore.  Only meaningful when the library was built
# with TX_R52_ENABLE_VFP and a floating-point ABI, so like the FVP's demo_m5.elf
# the target exists only in that configuration.  The FPU hardware enable lives in
# entry.S under __ARM_FP; tx_thread_vfp_enable() sets only the per-thread flag.
if(TX_R52_ENABLE_VFP)
    add_executable(s32z280_vfp.elf EXCLUDE_FROM_ALL
        ${EVB_DIR}/entry.S
        ${EVB_DIR}/tx_initialize_low_level.S
        ${EVB_DIR}/linflexd.c
        ${EVB_DIR}/timer.c
        ${EVB_DIR}/mpu.c
        ${EVB_DIR}/gicv3.c
        ${EVB_DIR}/irq_dispatch.c
        ${EVB_DIR}/gic_probe.c
        ${EVB_DIR}/cache.c
        ${EVB_DIR}/tcm.c
        ${EVB_DIR}/demo_vfp_s32z280.c
    )

    target_compile_definitions(s32z280_vfp.elf PRIVATE TX_R52_USE_THREADX_IRQ=1)
    target_compile_options(s32z280_vfp.elf PRIVATE -g)

    target_link_libraries(s32z280_vfp.elf PRIVATE threadx)

    target_include_directories(s32z280_vfp.elf PRIVATE
        ${EVB_DIR}
        ${CMAKE_SOURCE_DIR}/common/inc
        ${CMAKE_SOURCE_DIR}/ports/${THREADX_ARCH}/${THREADX_TOOLCHAIN}/inc
    )

    target_link_options(s32z280_vfp.elf PRIVATE
        -T${EVB_DIR}/link.lds
        -nostartfiles
        -Wl,-Map=s32z280_vfp.map
        ${EVB_LINK_QUIET_RWX}
    )
endif()

# Nested IRQ handling on silicon.  Needs the library built with
# TX_R52_ENABLE_IRQ_NESTING, since entry.S only emits the nesting_start and
# nesting_end pairing under that macro, so the image exists in that
# configuration only -- as s32z280_vfp.elf does for the floating-point ABI.
if(TX_R52_ENABLE_IRQ_NESTING)
    add_executable(s32z280_nesting.elf EXCLUDE_FROM_ALL
        ${EVB_DIR}/entry.S
        ${EVB_DIR}/tx_initialize_low_level.S
        ${EVB_DIR}/linflexd.c
        ${EVB_DIR}/timer.c
        ${EVB_DIR}/mpu.c
        ${EVB_DIR}/gicv3.c
        ${EVB_DIR}/irq_dispatch.c
        ${EVB_DIR}/gic_probe.c
        ${EVB_DIR}/cache.c
        ${EVB_DIR}/tcm.c
        ${EVB_DIR}/demo_nesting_s32z280.c
    )

    target_compile_definitions(s32z280_nesting.elf PRIVATE TX_R52_USE_THREADX_IRQ=1)
    target_compile_options(s32z280_nesting.elf PRIVATE -g)

    target_link_libraries(s32z280_nesting.elf PRIVATE threadx)

    target_include_directories(s32z280_nesting.elf PRIVATE
        ${EVB_DIR}
        ${CMAKE_SOURCE_DIR}/common/inc
        ${CMAKE_SOURCE_DIR}/ports/${THREADX_ARCH}/${THREADX_TOOLCHAIN}/inc
    )

    target_link_options(s32z280_nesting.elf PRIVATE
        -T${EVB_DIR}/link.lds
        -nostartfiles
        -Wl,-Map=s32z280_nesting.map
        ${EVB_LINK_QUIET_RWX}
    )
endif()

# Nested FIQ handling on silicon.  Needs TX_R52_ENABLE_FIQ_NESTING, which the
# port-level CMakeLists already requires TX_R52_ENABLE_FIQ alongside, so the image
# exists only where both the FIQ vector path and the nesting pairing are compiled
# in -- as s32z280_nesting.elf does for the IRQ side.
if(TX_R52_ENABLE_FIQ_NESTING)
    add_executable(s32z280_fiq.elf EXCLUDE_FROM_ALL
        ${EVB_DIR}/entry.S
        ${EVB_DIR}/tx_initialize_low_level.S
        ${EVB_DIR}/linflexd.c
        ${EVB_DIR}/timer.c
        ${EVB_DIR}/mpu.c
        ${EVB_DIR}/gicv3.c
        ${EVB_DIR}/irq_dispatch.c
        ${EVB_DIR}/gic_probe.c
        ${EVB_DIR}/cache.c
        ${EVB_DIR}/tcm.c
        ${EVB_DIR}/demo_fiq_s32z280.c
    )

    target_compile_definitions(s32z280_fiq.elf PRIVATE TX_R52_USE_THREADX_IRQ=1)
    target_compile_options(s32z280_fiq.elf PRIVATE -g)

    target_link_libraries(s32z280_fiq.elf PRIVATE threadx)

    target_include_directories(s32z280_fiq.elf PRIVATE
        ${EVB_DIR}
        ${CMAKE_SOURCE_DIR}/common/inc
        ${CMAKE_SOURCE_DIR}/ports/${THREADX_ARCH}/${THREADX_TOOLCHAIN}/inc
    )

    target_link_options(s32z280_fiq.elf PRIVATE
        -T${EVB_DIR}/link.lds
        -nostartfiles
        -Wl,-Map=s32z280_fiq.map
        ${EVB_LINK_QUIET_RWX}
    )
endif()
