/**
*   @copyright       © 2026 Microchip Technology Inc.
    Microchip Technology Inc. and its subsidiaries. You may use this
    software and any derivatives exclusively with Microchip products.

    THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, WHETHER
    EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, INCLUDING ANY IMPLIED
    WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, AND FITNESS FOR A
    PARTICULAR PURPOSE, OR ITS INTERACTION WITH MICROCHIP PRODUCTS, COMBINATION
    WITH ANY OTHER PRODUCTS, OR USE IN ANY APPLICATION.

    IN NO EVENT WILL MICROCHIP BE LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE,
    INCIDENTAL OR CONSEQUENTIAL LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND
    WHATSOEVER RELATED TO THE SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS
    BEEN ADVISED OF THE POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE
    FULLEST EXTENT ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN
    ANY WAY RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY,
    THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE.

    MICROCHIP PROVIDES THIS SOFTWARE CONDITIONALLY UPON YOUR ACCEPTANCE OF THESE
    TERMS. 
*
*************************************************************************/

/**
 *  @file       diag_cpu.h
 *  @version    1.0
 *  @brief      This file has the declarations for the CPU diagnostic 
 *              functions
 *
 *************************************************************************/
/**
 * @defgroup functions Functions
 * @defgroup macros Macros
 * @defgroup enums Enums
 * @defgroup global_variables Global Variables
*/
#ifndef DIAG_CPU_H
#define DIAG_CPU_H
#include<xc.h>
#include "diag.h"

/**
 * @ingroup global_variables
 * @brief Global variable holding the result of the most recent CPU diagnostic test.
 *
 * This external variable is used to store the result of the latest CPU diagnostic
 * operation. It can be accessed by multiple sub APIs to check the outcome of CPU self-tests
 * or other diagnostic routines.
 *
 * @note The values stored in this variable (e.g., DIAG_PASS, DIAG_FAIL) are
 *       defined in @see diag_cpu_self_test.c.
 */
extern volatile uint32_t DIAG_CPU_TestResult;

/**
 * @ingroup enums
 * @enum DIAG_CPU_CONTROL_REGISTER_TEST_FLAG_INDEX
 * @brief Enumeration of flag indices for CPU control register diagnostic tests.
 *
 * This enumeration defines symbolic indices for various CPU control and status registers
 * used in diagnostic test routines. Each enumerator corresponds to a specific CPU register
 * or special function register, and is typically used to index into status arrays or bitfields
 * that track the pass/fail status of individual register tests.
 *
 * The indices cover general-purpose working registers (W0-W15), accumulator registers,
 * special function registers, and various control/status registers relevant to CPU diagnostics.
 *
 * @var DIAG_W0_FLAG_INDEX      Index for Working Register W0.
 * @var DIAG_W1_FLAG_INDEX      Index for Working Register W1.
 * @var DIAG_W2_FLAG_INDEX      Index for Working Register W2.
 * @var DIAG_W3_FLAG_INDEX      Index for Working Register W3.
 * @var DIAG_W4_FLAG_INDEX      Index for Working Register W4.
 * @var DIAG_W5_FLAG_INDEX      Index for Working Register W5.
 * @var DIAG_W6_FLAG_INDEX      Index for Working Register W6.
 * @var DIAG_W7_FLAG_INDEX      Index for Working Register W7.
 * @var DIAG_W8_FLAG_INDEX      Index for Working Register W8.
 * @var DIAG_W9_FLAG_INDEX      Index for Working Register W9.
 * @var DIAG_W10_FLAG_INDEX     Index for Working Register W10.
 * @var DIAG_W11_FLAG_INDEX     Index for Working Register W11.
 * @var DIAG_W12_FLAG_INDEX     Index for Working Register W12.
 * @var DIAG_W13_FLAG_INDEX     Index for Working Register W13.
 * @var DIAG_W14_FLAG_INDEX     Index for Working Register W14.
 * @var DIAG_W15_FLAG_INDEX     Index for Working Register W15.
 * @var DIAG_SPLIM_FLAG_INDEX   Index for Stack Pointer Limit Register.
 * @var DIAG_ACCA_FLAG_INDEX    Index for Accumulator A Register.
 * @var DIAG_ACCB_FLAG_INDEX    Index for Accumulator B Register.
 * @var DIAG_SR_FLAG_INDEX      Index for Status Register.
 * @var DIAG_RCOUNT_FLAG_INDEX  Index for Repeat Count Register.
 * @var DIAG_DISIIPL_FLAG_INDEX Index for DISI IPL Register.
 * @var DIAG_CORCON_FLAG_INDEX  Index for CORCON Register.
 * @var DIAG_MODCON_FLAG_INDEX  Index for MODCON Register.
 * @var DIAG_XMODSRT_FLAG_INDEX Index for XMODSRT Register.
 * @var DIAG_XMODEND_FLAG_INDEX Index for XMODEND Register.
 * @var DIAG_YMODSRT_FLAG_INDEX Index for YMODSRT Register.
 * @var DIAG_YMODEND_FLAG_INDEX Index for YMODEND Register.
 * @var DIAG_XBREV_FLAG_INDEX   Index for XBREV Register.
 * @var DIAG_PCTRAP_FLAG_INDEX Index for PCTRAP Register.
 * @var DIAG_FEX_FLAG_INDEX    Index for FEX Register.
 * @var DIAG_FEX2_FLAG_INDEX   Index for FEX2 Register.
 * @var DIAG_PCHOLD_FLAG_INDEX Index for PCHOLD Register.
 * @var DIAG_VFA_FLAG_INDEX    Index for VFA Register.
 */
typedef enum
    {
        DIAG_W0_FLAG_INDEX,
        DIAG_W1_FLAG_INDEX,
        DIAG_W2_FLAG_INDEX,
        DIAG_W3_FLAG_INDEX,
        DIAG_W4_FLAG_INDEX,
        DIAG_W5_FLAG_INDEX,
        DIAG_W6_FLAG_INDEX,
        DIAG_W7_FLAG_INDEX,
        DIAG_W8_FLAG_INDEX,
        DIAG_W9_FLAG_INDEX,
        DIAG_W10_FLAG_INDEX,
        DIAG_W11_FLAG_INDEX,
        DIAG_W12_FLAG_INDEX,
        DIAG_W13_FLAG_INDEX,
        DIAG_W14_FLAG_INDEX,
        DIAG_W15_FLAG_INDEX,
        DIAG_SPLIM_FLAG_INDEX,  
        DIAG_ACCA_FLAG_INDEX,
        DIAG_ACCB_FLAG_INDEX,
        DIAG_SR_FLAG_INDEX,
        DIAG_RCOUNT_FLAG_INDEX,
        DIAG_DISIIPL_FLAG_INDEX,
        DIAG_CORCON_FLAG_INDEX,
        DIAG_MODCON_FLAG_INDEX,
        DIAG_XMODSRT_FLAG_INDEX,
        DIAG_XMODEND_FLAG_INDEX,
        DIAG_YMODSRT_FLAG_INDEX,
        DIAG_YMODEND_FLAG_INDEX,
        DIAG_XBREV_FLAG_INDEX,
        DIAG_PCTRAP_FLAG_INDEX,
        DIAG_FEX_FLAG_INDEX,    
        DIAG_FEX2_FLAG_INDEX,  
        DIAG_PCHOLD_FLAG_INDEX,   
        DIAG_VFA_FLAG_INDEX         
    } DIAG_CPU_CONTROL_REGISTER_TEST_FLAG_INDEX;

/**
 * @ingroup enums
 * @enum DIAG_CPU_SELF_TEST_SUBSET
 * @brief Enumeration of CPU self-test subset identifiers.
 *
 * This enumeration defines the possible subsets of CPU self-tests that can be executed
 * individually or collectively. Each enumerator represents a specific group of diagnostic
 * tests targeting different CPU components or functionalities. The enumeration also includes
 * options to execute all subsets or to indicate an invalid subset selection.
 *
 * @var DIAG_CPU_SELF_TEST_SUBSET_1         Identifier for CPU self-test subset 1.
 * @var DIAG_CPU_SELF_TEST_SUBSET_2         Identifier for CPU self-test subset 2.
 * @var DIAG_CPU_SELF_TEST_SUBSET_3         Identifier for CPU self-test subset 3.
 * @var DIAG_CPU_SELF_TEST_SUBSET_4         Identifier for CPU self-test subset 4.
 * @var DIAG_CPU_SELF_TEST_SUBSET_5         Identifier for CPU self-test subset 5.
 * @var DIAG_CPU_SELF_TEST_SUBSET_6         Identifier for CPU self-test subset 6.
 * @var DIAG_CPU_SELF_TEST_SUBSET_7         Identifier for CPU self-test subset 7.
 * @var DIAG_CPU_SELF_TEST_SUBSET_8         Identifier for CPU self-test subset 8.
 * @var DIAG_CPU_SELF_TEST_ALL              Identifier to execute all self-test subsets.
 * @var DIAG_CPU_SELF_TEST_SUBSET_INVALID   Identifier for an invalid or undefined subset.
 */    
     typedef enum
    {
        DIAG_CPU_SELF_TEST_SUBSET_1,
        DIAG_CPU_SELF_TEST_SUBSET_2,
        DIAG_CPU_SELF_TEST_SUBSET_3,
        DIAG_CPU_SELF_TEST_SUBSET_4,
        DIAG_CPU_SELF_TEST_SUBSET_5,
        DIAG_CPU_SELF_TEST_SUBSET_6,
        DIAG_CPU_SELF_TEST_SUBSET_7,
        DIAG_CPU_SELF_TEST_SUBSET_8,  
        DIAG_CPU_SELF_TEST_ALL,
        DIAG_CPU_SELF_TEST_SUBSET_INVALID 
    } DIAG_CPU_SELF_TEST_SUBSET;
    
/**
 * @ingroup global_variables
 * @brief Global flag indicating the occurrence of a CPU math error.
 *
 * This external, volatile variable is set when a math error (such as overflow, underflow,
 * or divide-by-zero) is detected during CPU operation or self-test routines.
 * It can be checked by diagnostic or application code to determine if a math error has occurred.
 *
 * @note The variable is declared as volatile because it may be modified by interrupt service routines
 *       or hardware, and should not be optimized out by the compiler.
 */
extern volatile uint16_t DIAG_CPU_MathErrorFlag;

/**
 * @ingroup global_variables
 * @brief Status flags for CPU control register diagnostic tests.
 *
 * This external, volatile 64-bit variable is used as a bitfield to record the pass/fail status
 * of individual CPU control register tests. Each bit corresponds to a specific register or test,
 * where a '1' typically indicates a failure and a '0' indicates a pass.
 *
 * @note The mapping of bits to specific registers or tests is defined elsewhere in the codebase.
 *       The variable is declared as volatile because it may be updated by different parts of the program,
 *       including interrupt service routines.
 */
extern volatile uint64_t diagCpuControlRegStatusFlags;

/**
 * @ingroup macros
 * @def DIAG_CPU_TEST_EXECUTION_IN_PROGRESS
 * @brief Macro indicating that a CPU self-test is currently in progress.
 *
 * This macro defines a constant value (0x5555U) used to represent the state where
 * a CPU self-test routine is actively executing. It can be used to check or set the
 * execution status in diagnostic routines.
 */
#define DIAG_CPU_TEST_EXECUTION_IN_PROGRESS 0x5555U

/**
 * @ingroup macros
 * @def DIAG_CPU_TEST_EXECUTION_COMPLETE
 * @brief Macro indicating that a CPU self-test has completed.
 *
 * This macro defines a constant value (0xAAAAU) used to represent the state where
 * a CPU self-test routine has finished execution. It can be used to check or set the
 * execution status in diagnostic routines.
 */
#define DIAG_CPU_TEST_EXECUTION_COMPLETE 0xAAAAU

    
     // TestSubset_1
    __asm__ (".equ _DIAG_CPU_Test1Data0, 0xAD700000");
    __asm__ (".equ _DIAG_CPU_Test1Data1, 0xB29F");
    __asm__ (".equ _DIAG_CPU_Test1Data2, 0xFE");
    __asm__ (".equ _DIAG_CPU_Test1Data3, 0x01");
        // TestSubset_2
    __asm__ (".equ _DIAG_CPU_Test2Data1, 0x00FF");
    __asm__ (".equ _DIAG_CPU_Test2Data2, 0x0002");
    __asm__ (".equ _DIAG_CPU_Test2Data3, 0x55555555");
    __asm__ (".equ _DIAG_CPU_Test2Data4, 0xAAAAAAAA");
    __asm__ (".equ _DIAG_CPU_Test2Data5, 0x0001");
    __asm__ (".equ _DIAG_CPU_Test2Data6, 0xFFFF");
    
    // TestSubset_3
    __asm__ (".equ _DIAG_CPU_Test3Data1, 0x00000006"); 
    __asm__ (".equ _DIAG_CPU_Test3Data25, 0x00000007");
    __asm__ (".equ _DIAG_CPU_Test3Data2, 0x000000F4");
    __asm__ (".equ _DIAG_CPU_Test3Data3, 0x00000004");
    __asm__ (".equ _DIAG_CPU_Test3Data26,0x00000006");
    __asm__ (".equ _DIAG_CPU_Test3Data4, 0x00000011");
    __asm__ (".equ _DIAG_CPU_Test3Data5, 0x00000022");
    __asm__ (".equ _DIAG_CPU_Test3Data6, 0x00000033");
    __asm__ (".equ _DIAG_CPU_Test3Data7, 0x00000044");
    __asm__ (".equ _DIAG_CPU_Test3Data8, 0x00000055");
    __asm__ (".equ _DIAG_CPU_Test3Data9, 0x00000066");
    __asm__ (".equ _DIAG_CPU_Test3Data10, 0x00000077");
    __asm__ (".equ _DIAG_CPU_Test3Data11, 0x00000088");
    __asm__ (".equ _DIAG_CPU_Test3Data12, 0x00000099");
    __asm__ (".equ _DIAG_CPU_Test3Data13, 0x000000AA");
    __asm__ (".equ _DIAG_CPU_Test3Data14, 0x000000BB");
    __asm__ (".equ _DIAG_CPU_Test3Data15, 0x000000CC");
    __asm__ (".equ _DIAG_CPU_Test3Data16, 0x000000DD");
    __asm__ (".equ _DIAG_CPU_Test3Data17, 0x000000ED");
    __asm__ (".equ _DIAG_CPU_Test3Data18, 0x000000FF");
    __asm__ (".equ _DIAG_CPU_Test3Data19, 0x00000040");
    __asm__ (".equ _DIAG_CPU_Test3Data20, 0x00000057");
    __asm__ (".equ _DIAG_CPU_Test3Data21, 0x5555AAAA");
    
    // TestSubset_4
    __asm__ (".equ _DIAG_CPU_Test4Data1, 0x1FF");
    __asm__ (".equ _DIAG_CPU_Test4Data2, 0x1F");
    __asm__ (".equ _DIAG_CPU_Test4Data3, 0xAA");
    __asm__ (".equ _DIAG_CPU_Test4Data4, 0x19");
    __asm__ (".equ _DIAG_CPU_Test4Data5, 0x13");
    __asm__ (".equ _DIAG_CPU_Test4Data6, 0x09");
    __asm__ (".equ _DIAG_CPU_Test4Data7, 0x13");
    __asm__ (".equ _DIAG_CPU_Test4Data8, 0x01");
    __asm__ (".equ _DIAG_CPU_Test4Data9, 0x07");
    __asm__ (".equ _DIAG_CPU_Test4Data10, 0x8000");
    __asm__ (".equ _DIAG_CPU_Test4Data11, 0x7FFF");
    
    // TestSubset_5
    __asm__ (".equ _DIAG_CPU_Test5Data1, 0x3FF");
    __asm__ (".equ _DIAG_CPU_Test5Data2, 0x1F");
    __asm__ (".equ _DIAG_CPU_Test5Data3, 0x1234");
    __asm__ (".equ _DIAG_CPU_Test5Data4, 0xAAAAFFAA");
    __asm__ (".equ _DIAG_CPU_Test5Data5, 0x0000000A");

    // TestSubset_6
    __asm__ (".equ _DIAG_CPU_Test6Data1, 0xF042");
    __asm__ (".equ _DIAG_CPU_Test6Data2, 0x8001");
    __asm__ (".equ _DIAG_CPU_Test6Data3, 0x0007");
    __asm__ (".equ _DIAG_CPU_Test6Data4, 0x001F");
    __asm__ (".equ _DIAG_CPU_Test6Data5, 0x00F0");
    __asm__ (".equ _DIAG_CPU_Test6Data6, 0x0005");

    // TestSubset_7
    __asm__ (".equ _DIAG_CPU_Test7Data1, 0x1234");
    __asm__ (".equ _DIAG_CPU_Test7Data2, 0x6");
    __asm__ (".equ _DIAG_CPU_Test7Data3, 0x00AAAAAA");
    __asm__ (".equ _DIAG_CPU_Test7Data4, 0x00555555");

    // TestSubset_8
    __asm__ (".equ _DIAG_CPU_Test8Data1, 0x273C");
    __asm__ (".equ _DIAG_CPU_Test8Data2, 0x7F54");
    __asm__ (".equ _DIAG_CPU_Test8Data3, 0x8FF3");
    __asm__ (".equ _DIAG_CPU_Test8Data4, 0x545404FF");
    __asm__ (".equ _DIAG_CPU_Test8Data5, 0x8001");
    __asm__ (".equ _DIAG_CPU_Test8Data6, 0x00AC");
    __asm__ (".equ _DIAG_CPU_Test8Data7, 0x4FAF");
    __asm__ (".equ _DIAG_CPU_Test8Data8, 0x0005");
    __asm__ (".equ _DIAG_CPU_Test8Data9, 0x0002");

/**
 * @ingroup functions
 * @brief **Software Requirement Reference ID : SW_CPU_REGISTER_RESET_STATE_TEST_01**\n
 * Tests the reset state of CPU registers against expected values.
 *
 * This function verifies that a set of CPU registers are in their expected reset state
 * by comparing their current values (masked with a reset mask) to the expected reset values.
 * The function iterates through a lookup table containing the expected reset values and masks
 * for each register. If a register does not match its expected reset value, the function
 * increments a failure counter and attempts to restore the register to its expected reset state.
 *
 * The function uses a pointer to a CPU register map to access the registers. After checking all
 * registers, it sets a diagnostic return value to indicate pass or fail, depending on whether
 * any mismatches were found. The result is then returned to the caller.
 *
 * The function is typically used as part of a diagnostic or self-test routine to ensure
 * that CPU registers are correctly reset after a system reset or during initialization.
 *
 * @note The function assumes that the CPU register map and the reset value lookup table
 *       are correctly defined and accessible. It also assumes that the DIAG_CPU_SetRetValue()
 *       and DIAG_CPU_GetRetValue() functions are implemented to handle diagnostic results.
 *
 * @return uint32_t Returns the diagnostic result:
 *         - DIAG_PASS if all registers are in their expected reset state.
 *         - DIAG_FAIL if any register does not match its expected reset value.
 * @par
   Imageref DIAG_CPU_RegResetStateTest_UML.svg "CPU Reg Reset State Test Sequence Diagram"
   Imageref DIAG_CPU_RegResetStateTest_ClassDiagram.svg "CPU Reg Reset State Test Class Diagram"
 */    
uint32_t DIAG_CPU_RegResetStateTest(void);

/**
 * @ingroup functions
 * @brief **Software Requirement Reference ID : SW_CPU_CONTROL_REGISTER_TEST_01**\n
 * Tests the functionality of CPU control registers by writing and verifying test patterns.
 *
 * This function performs a comprehensive test of the CPU's control registers to ensure their
 * correct operation. It uses a lookup table containing two test values and a mask for each register.
 * For each register that is not read-only, the function:
 *   - Saves the current register value.
 *   - Writes the first test value and verifies that the register correctly stores and returns the value (masked).
 *   - Writes the second test value and verifies it similarly.
 *   - Restores the original register value after testing.
 *   - If a register fails to store or return the expected value, a status flag is set for that register.
 *
 * The function also saves and restores the interrupt control register (INTCON2) to ensure that
 * interrupts are disabled during the test, preventing interference.
 *
 * Registers that are read-only or not tested are skipped (indicated by zero test values in the lookup table).
 * The function calls an auxiliary test for non-memory-mapped control registers as well.
 *
 * At the end of the test, the function sets a diagnostic result (pass/fail) based on whether any
 * register failed the test, and returns this result.
 *
 * @note The function assumes that the CPU register map, control test lookup table, and related
 *       diagnostic functions/macros are correctly defined and accessible. It also assumes that
 *       the DIAG_CPU_SetRetValue() and DIAG_CPU_GetRetValue() functions are implemented to handle
 *       diagnostic results.
 *
 * @return uint32_t Returns the diagnostic result:
 *         - DIAG_PASS if all tested registers pass the test.
 *         - DIAG_FAIL if any tested register fails.
 * @par
   Imageref DIAG_CPU_ControlRegTest_UML.svg "CPU Control Register Test Sequence Diagram"
   Imageref DIAG_CPU_ControlRegTest_ActivityDiagram.svg "CPU Control Register Test Activity Diagram"
 */
uint32_t DIAG_CPU_ControlRegTest(void);

/**
 * @ingroup functions
 * @brief **Software Requirement Reference ID : SW_CPU_SELF_TEST_01**\n
 * Executes a comprehensive or subset-based CPU self-test routine.
 *
 * This function performs a self-test of the CPU by executing a series of diagnostic test subsets,
 * depending on the specified execution mode. It is designed to verify the integrity and correct
 * operation of various CPU components, including memory-mapped and non-memory-mapped registers,
 * as well as RAM regions used for diagnostics.
 *
 * The function begins by saving the current interrupt control state and disabling global interrupts
 * to ensure atomicity and prevent interference during the self-test. It then saves the contents of
 * specific test RAM regions to a temporary array using inline assembly, preserving their state for
 * later restoration.
 * 
 * The overall self-test algorithm is subdivided into eight Test Subset functions (each representing 
 * a different subset of CPU functionality). Each individual subset can be executed and this execution
 * mode is labelled CPU_SELF_TEST_SUBSET with the suffix of the corresponding subset index.Alternately, 
 * all the Test Subset functions may be executed during a single API call. This execution mode is labeled
 * CPU_SELF_TEST_ALL. The API allows the user to choose either of the above modes of execution through the choice of API function argument.
 *
 * The self-test can be executed in three modes:
 *   - **DIAG_CPU_SELF_TEST_ALL**: All available test subsets are executed sequentially. The pass/fail
 *     status of each subset is recorded, and the overall result is set to pass only if all subsets pass.
 *   - **DIAG_CPU_SELF_TEST_SUBSET_INVALID**: If an invalid subset is specified, the function returns
 *     an invalid parameter result.
 *   - **Specific Subset**: Only the specified test subset is executed, and its result is returned. 
 * The corresponding enum variables in the enum list are passed as argument. @ref DIAG_CPU_SELF_TEST_SUBSET for the list of options
 *
 * After the self-test execution, the function restores the original contents of the test RAM regions
 * using inline assembly and re-enables interrupts by restoring the saved interrupt control state.
 * The function then returns the overall diagnostic result.
 * 
 * The CPU instructions and features tested within each Test Subset function are listed below. \n
 *  (a) Test Subset 1: @ref DIAG_CPU_SELF_TEST_SUBSET DIAG_CPU_SELF_TEST_SUBSET_1 \n
 *     - All of the MOV instructions are tested \n
 *     - Addressing modes tested: Immediate, File Register, Register Direct and Indirect (with 
 *        pre-increment, post-increment, pre-decrement, post-decrement, literal offset and register offset) \n
 *     - SWAP and EXCH instructions are tested \n
 *     - All bit manipulation, bit test and bit-compare-skip operations are tested \n
 *     - Single-word and double-word instructions are tested \n
 *     - Byte MOV instructions are also checked \n
 *  (b) Test Subset 2: @ref DIAG_CPU_SELF_TEST_SUBSET DIAG_CPU_SELF_TEST_SUBSET_2 \n
 *     - PSV and table accesses from different sections (four locations) of program memory \n
 *     - All bits of the program memory address bus are toggled \n
 *     - All bits of the data memory address bus are toggled \n
 *     - All bits of the X data read and write buses are toggled \n
 *     - CPU registers tested for read/write operations are: W0-W15, SPLIM, TBLPAG, PSVPAG/DSRPAG \n
 *     - Read-After-Write (RAW) dependency \n
 *     - NOP and NOPR instructions \n
 *  (c) Test Subset 3: @ref DIAG_CPU_SELF_TEST_SUBSET DIAG_CPU_SELF_TEST_SUBSET_3 \n
 *     - All conditional branch and GOTO instructions with alternative conditions \n
 *     - Program Counter (PC) behavior during above program flow change operations \n
 *     - All CALL and RETURN operations \n
 *     - Automatic context save on stack \n
 *     - All stack and shadow operations \n
 *     - DISI instruction \n
 *  (d) Test Subset 4: @ref DIAG_CPU_SELF_TEST_SUBSET DIAG_CPU_SELF_TEST_SUBSET_4 \n
 *     - Branch instructions tested for false condition are NOV, Z, NN, NC and NZ \n
 *     - All logic instructions: AND, CLR, COM, IOR, NEG, SETM and XOR instructions \n
 *     - All data rotate and shift instructions \n
 *     - All compare and compare-skip instructions \n
 *     - The Z, OV, DC, N and C bits of the STATUS Register are checked for their behavior \n
 *     - Some Byte mode logic instructions are tested \n
 *  (e) Test Subset 5: @ref DIAG_CPU_SELF_TEST_SUBSET DIAG_CPU_SELF_TEST_SUBSET_5 \n
 *     - The following arithmetic instructions are tested: ADD, ADDC, SUB, SUBB, SUBBR, INC,
 *     INC2, DEC, DEC2, SE, ZE \n
 *     - The addressing modes tested here are: Immediate, File Register, Register Direct \n
 *     - Byte instructions are also checked \n
 *     - Branch instructions tested for True condition are: GT, GTU, LE, LEU, NC, NN, OV \n
 *     - Branch instructions tested for False condition are: C, GE, GEU, LT, LTU, N, NOV \n
 *     - Divide Unsigned Double (DIV.UD) instruction \n
 *  (f) Test Subset 6: @ref DIAG_CPU_SELF_TEST_SUBSET DIAG_CPU_SELF_TEST_SUBSET_6 \n
 *     - All MUL instruction variants \n
 *     - All DIV instruction variants except DIVF and DIV.UD \n
 *     - REPEAT loop \n
 *     - Math error trap generation (divide-by-zero error) \n
 *  (g) Test Subset 7: @ref DIAG_CPU_SELF_TEST_SUBSET DIAG_CPU_SELF_TEST_SUBSET_7 \n
 *     - All DSP accumulator operations, including different bit states of the individual bits
 *       of both accumulators \n
 *     - All DSP multiplier-based instructions \n
 *     - All DSP MAC Register Indirect Addressing modes \n
 *     - All DSP shift instructions \n
 *     - Math error trap generation due to accumulator-related events (accumulator overflow
 *     and catastrophic overflow) \n
 *     - CORCON bit behavior \n
 *  (h) Test Subset 8: @ref DIAG_CPU_SELF_TEST_SUBSET DIAG_CPU_SELF_TEST_SUBSET_8 \n
 *     - Modulo Addressing (both Byte and Word modes) \n
 *     - Bit-Reversed Addressing \n
 *     - DO loop \n
 *     - Fractional Divide (DIVF) instruction
 *
 * @param[in] executionMode Specifies which self-test subset(s) to execute. This can be:
 *            - DIAG_CPU_SELF_TEST_ALL: Execute all test subsets.
 *            - DIAG_CPU_SELF_TEST_SUBSET_INVALID: Invalid subset (returns error).
 *            - Any valid subset index: Execute only the specified subset.
 *
 * @return uint32_t Returns the diagnostic result:
 *         - DIAG_PASS if all executed test subsets pass.
 *         - DIAG_FAIL if any executed test subset fails.
 *         - DIAG_INVALID_PARAM if an invalid subset is specified.
 *
 * @note The function uses inline assembly to save and restore RAM regions critical to the self-test.
 *       It also relies on external diagnostic functions and status variables to manage and report
 *       the results of each test subset.
 *       The function disables and restores interrupts to ensure test integrity.
 * @par
   Imageref DIAG_CPU_SelfTest_UML.svg "CPU Self Test Sequence Diagram"
   Imageref DIAG_CPU_SelfTest_ClassDiagram.svg "CPU Self Test Class Diagram"
 */
uint32_t DIAG_CPU_SelfTest(DIAG_CPU_SELF_TEST_SUBSET executionMode);

/**
 * @ingroup functions
 * @brief Retrieves the most recent pass/fail status of CPU self-test subsets.
 *
 * This function returns the status word that indicates the result of the most recently executed
 * CPU self-test subsets. Each bit in the returned value corresponds to a specific test subset:
 *   - A bit value of '1' indicates that the corresponding test subset has failed.
 *   - A bit value of '0' indicates that the corresponding test subset has passed.
 *
 * This function is typically used after running the CPU self-test routine to determine which
 * (if any) test subsets have failed.
 * 
 * 
 *
 * @return uint32_t A status word where each bit represents the pass/fail status of a test subset:
 *         - '1' = Fail
 *         - '0' = Pass
 *
 * @note The mapping of bits to test subsets is as follows. The Least significant bit indicates the
 * subset0, the next bit subset1 and so on.
 */
uint32_t DIAG_CPU_SelfTest_GetStatus(void);

/**
 * @ingroup functions
 * @brief Handles math error conditions during CPU self-test or delegates to user-defined handler.
 *
 * This function checks the current status of the CPU self-test execution. If a math error occurs
 * while the self-test is in progress, it calls the internal diagnostic math error handler
 * (`DIAG_CPU_MathError`). If the self-test is not in progress, it calls a user-provided math error
 * handler function, allowing the application to handle math errors according to its own logic.
 *
 * The function is marked with `__attribute__((optimize(0)))` to disable compiler optimizations,
 * ensuring predictable behavior for diagnostic and coverage analysis purposes.
 *
 * @param[in] userMathError Pointer to a user-defined function that handles math errors
 *            when the self-test is not in progress. This function should take no arguments
 *            and return void.
 *
 * @return void
 *
 * @note This function is typically used as a wrapper for math error handling, ensuring that
 *       errors are processed appropriately depending on whether the CPU self-test is running.
 *       If the self-test is running, only the internal handler is called to maintain test integrity.
 *       Otherwise, the user-defined handler is invoked.
 */
void  DIAG_CPU_CheckFlagMathError(void (*userMathError)());

#endif /* DIAG_CPU_H */
