/**
 *   @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_shared.c
 *  @version         1.0
 *  @brief           This file has the common implementation for the CPU APIs.
                      @see diag_cpu_shared.h
 *
 *************************************************************************/
#include "diag_cpu.h"
#include "diag_cpu_shared.h"

static uint32_t cpuInternalRetVal;
/*LDRA_NOANALYSIS*/

/* Note: The following 3 functions are dummy/wrapper functions, so the C entry/exit into these functions
         will therefore not expected to get executed. It is the inline-assembly code inside these wrapper
         functions that will be directly executed as part of the testing of the CALL/RCALL instructions.
         Hence, these 3 functions must be excluded from Static and Dynamic Analysis. */

/* ..............................................................................
 Sub Routine Section for TestSubset3:
 ..............................................................................
 1. The automatic context save on stack is tested.
 2. Move address pointer value to w7.
 3. With the help of w7 read the PCH and PCL which are saved on stack.
 4. Link frame pointer. Allocate 64 bytes.
 5. The LNK and ULNK are tested w.r.t w15.
 6. The saving/retrieving of w14 to/from stack will increment/decrement w15
    irrespective of contents of w14.
 7. The value w7 is subtracted from w15 to get a constant which validates LNK,
    is added to w0.
 8. Similarly ULNK will affect w15. once again w7 is subtracted from w15 to
    get a constant which validates ULNK, is added to w0.
 .............................................................................. */
/*LDRA_EXCLUDE 76 D <justification start>Function called as function pointer, wrongly reported by tool, violation ignored <justification end> */
/*LDRA_EXCLUDE 61 D <justification start>Tool reporting wrongly to declare as static because of above, violation ignored <justification end> */
/*LDRA_EXCLUDE 65 D <justification start>Wrapper function used to wrap the assembly instructions. Violation Ignored.<justification end> */
/*LDRA_EXCLUDE 106 D <justification start>Function called from assembly instruction, declaration not needed, violation ignored <justification end> */
static void __attribute__((keep, optimize(0))) CPU_Wrapper_CALL_1(void) {
    __asm__ volatile ("_CALL_1: mov     w15, w7\n\t"
            "lnk     #_DIAG_CPU_Test3Data19\n\t" /* link frame pointer (0x40)
                                                     To avoid stall after one instruction */
            "add.l     w0, [--w7], w0\n\t" /* PCH and PCL are read and added to w0 */
            "add.l     w0, [--w7], w0\n\t"
            "sub.l     w15, w7, w5\n\t"
            "add.l     w0, w5, w0\n\t"
            "ulnk\n\t" /* Unlink frame pointer */
            "sub.l     w15, w7, w5\n\t"
            "add.l     w0, w5, w0\n\t"
            "return\n\t"
            );
}

/* ..............................................................................
 1. w0 contains the running 16-bit result which is saved on stack.
 2. w0-w3 and SR bits(DC,N,OV,Z,C) are modified at least once before being
    retrieved with pop.s instruction.
 3. pop.s will retrieve all w0-w3 registers and SR(DC,N,OV,Z,C) bits.
    i.e w0=0x0F, w1=0xF4, w2=0xC000, w3=0x03, SR bits DC,N,OV,Z,C all '0'.
    The w0-w3 and SR bits will be read by some means and used
    to affect the result will which will validate push.s and pop.s.
    w0(0xF) will validate DISICNT, w2(C000) will validate INTCON2 bits.
 4. The running 16-bit result is saved to location 0x1100 from
    the stack(push w0).
 5. The SR bits are and'ed with w0(which will validate SR bits and DISICNT).
    w0 contains partial results which validates SR and w1 after pop.s
 6. The running 16-bit result value is saved on to the stack from
    the location 0x1100. Next it is saved to w6 (if w6 contains correct running
    16-bit result then it will validate 'push ws, pop f, push f, pop wd').
    The w0 and w6 are added to w0. Now w0 contains the running 16-bit result.
 7. push.D and pop.D are used to the read the contents of w2:w3,
    which are saved to w4:w5.
 8. w4 and w5 are added to w0 which will validate push.D and pop.D
    and w2, w3 after pop.s
 .............................................................................. */

/*LDRA_EXCLUDE 76 D <justification start>Function called as function pointer, wrongly reported by tool, violation ignored <justification end> */
/*LDRA_EXCLUDE 61 D <justification start>Tool reporting wrongly to declare as static because of above, violation ignored <justification end> */
/* LDRA_EXCLUDE 65 D <justification start>Wrapper function used to wrap the assembly instructions. Violation Ignored.<justification end> */
/*LDRA_EXCLUDE 106 D <justification start>Function called from assembly instruction, declaration not needed, violation ignored <justification end> */
static void __attribute__((keep, optimize(0))) CPU_Wrapper_CALL_2(void) {
    __asm__ volatile ("_CALL_2: push    w0\n\t" /* save running 16-bit result on stack */
            /* Will retrieve all w0-w3 and SR (DC,N,OV,Z,C),
            //                                                     save running 16-bit result to */
            "pop     _DIAG_CPU_TestRam\n\t" /* the location 0x1100 */
            "mov SR,w2\n\t"
            "and.l     w2, w0,w0\n\t" /* w0=0xF, SR=0x0 */
            "push    _DIAG_CPU_TestRam\n\t" /* save running 16-bit result to stack */
            "add.l     w1, w0, w0\n\t" /* w1 is added to w0. */
            "pop     w6\n\t" /* To avoid stall, after one instruction the result is moved to w6. */
            "add.l     w0, w6, w0\n\t" /* w0 contains partial results which validates SR and w1 after pop.s */
            "push.l  w2\n\t"
            "pop.l   w4\n\t" /* CPU stall RAW detection, destination indirect with modification
//                                                      and source indirect with modification */
            "add     w4, w5, w4\n\t"
            "add.l     w0, w4, w0\n\t"
            "return\n\t");
}

/* ..............................................................................
    The retlw is used to return a constant value to w5 which will be later
    added to the running 16-bit result.
    This will validate Relative call and retlw.
 .............................................................................. */

/*LDRA_EXCLUDE 76 D <justification start>Function called as function pointer, wrongly reported by tool, violation ignored <justification end> */
/*LDRA_EXCLUDE 61 D <justification start>Tool reporting wrongly to declare as static because of above, violation ignored <justification end> */
/* LDRA_EXCLUDE 65 D <justification start>Wrapper function used to wrap the assembly instructions. Violation Ignored.<justification end> */
/*LDRA_EXCLUDE 106 D <justification start>Function called from assembly instruction, declaration not needed, violation ignored <justification end> */
static void __attribute__((keep, optimize(0))) CPU_Wrapper_RCALL_1(void) {
    __asm__ volatile ("_RCALL_1: retlw   #_DIAG_CPU_Test3Data20, w5");
}
/*LDRA_ANALYSIS*/

void DIAG_CPU_SetRetValue(uint32_t returnValue) {
    cpuInternalRetVal = returnValue;
}

uint32_t DIAG_CPU_GetRetValue(void) {
    return cpuInternalRetVal;
}

/*LDRA_NOANALYSIS*/
/*LDRA_EXCLUDE 76 D <justification start>Function called as function pointer, wrongly reported by tool, violation ignored <justification end> */
/*LDRA_EXCLUDE 61 D <justification start>Tool reporting wrongly to declare as static because of above, violation ignored <justification end> */
uint32_t DIAG_CPU_SelfTest_Subset1(void) {
    uint32_t result;
    uint8_t subset1Res;
    __asm__ volatile ("push w0\n\t"
            "push w1\n\t"
            "push w2\n\t"
            "push w3\n\t"
            "push w4\n\t"
            "push w5\n\t"
            "push w6\n\t"
            "push w7\n\t"

            /*..............................................................................
             MOVE BLOCK:
             0xb29f is moved to w1.The value is so chosen that
             when it is moved to a file register and execution of
             'mov f' instruction from the file reg to same file
             reg affects the 'N' bit of status register.
            ..............................................................................*/

            "clr w2\n\t"
            "clr w7\n\t"
            "clr _DIAG_CPU_TestRam\n\t"
            "clr _DIAG_CPU_TestRam+4\n\t"
            "clr _DIAG_CPU_TestRam+8\n\t"

            "mov.l #_DIAG_CPU_Test1Data0,w3\n\t"
            "mov #_DIAG_CPU_Test1Data1,w1\n\t"
            "mov.b #_DIAG_CPU_Test1Data2,w2\n\t"

            "mov w1, _DIAG_CPU_TestRam\n\t"
            "tst _DIAG_CPU_TestRam\n\t"
            "mov.l SR,w5\n\t"
            "btst.bC w5,#1\n\t"/*SG:test SR N bit*/
            "mov.l _DIAG_CPU_TestRam, w0\n\t"

            "mov.l w3, _DIAG_CPU_TestRam\n\t"
            "tst.l _DIAG_CPU_TestRam,w5\n\t"

            "add.l w5,w0,w0\n\t"
            "mov.l w0, _DIAG_CPU_TestRam\n\t"
            "btst.b _DIAG_CPU_TestRam,#5\n\t"/*file reg btst test, if set Z is set*/
            "mov.l SR,w5\n\t"
            "btst w5,#1\n\t"
            "mov w5,w6\n\t"
            "mov #_DIAG_CPU_TestRam,w5\n\t"
            "add.l w2,w5,w2\n\t"

            "mov.b [w2 - 0xfe], w3\n\t"
            "sub.l w0,w3,w0\n\t"
            "swap w0\n\t"
            "add.l w0,w6,w0\n\t"
            "mov.l w0, _DIAG_CPU_TestRam+4\n\t"
            "mov.l w2, _DIAG_CPU_TestRam+8\n\t"
            "mov.w w0,[w5+0xC]\n\t"
            "mov w5,w4\n\t"
            "mov.l [w5+0x4],w6\n\t"
            "mov.l w6,[w4+0x8]\n\t"
            "sl w5,w4\n\t"
            "add #_DIAG_CPU_Test1Data3,w4\n\t"
            "exch w4,w6\n\t"
            "add.l w0,w6,w0\n\t"
            "mov.l [w5++],w2\n\t"
            "mov w6,[w5+0x8]\n\t"
            "mov.l w5,w4\n\t"
            "add.l w5,#4,w5\n\t"
            "mov [--w5],[++w4]\n\t"
            "mov  w5,w6\n\t"
            "add #_DIAG_CPU_Test1Data3,w3\n\t"
            "swap.b w3\n\t"
            "mov.b w5,[w4]\n\t"
            "mov   w2,w0\n\t"
            "mov [w3+w6],[w3+w4]\n\t"
            "movr [++w4],[++w5]\n\t"
            /*..............................................................................
             Bit test and bit manipulation block
            ..............................................................................*/

            "bclr _DIAG_CPU_TestRam+4,#1\n\t"
            "bclr w1,#1\n\t" /* w1 contains 0x1106. On clearing the 2nd bit, w1 will have 0x1104. */
            "bset _DIAG_CPU_TestRam+4,#3\n\t" /* Setting the 4th bit in file register. */
            "bset w1,#0\n\t" /* Setting the 1st bit in w1. */
            "btst _DIAG_CPU_TestRam+4,#4\n\t" /* Bit test 5th bit in file register 0x1102 and the
                                               complement is stored in Z bit of SR. This doesn't
                                               alter the content of 0x1102. 0x1102 has 0xb208.
                                               So here Z bit gets set and SR contains 0x0002. */
            "bsw.z w4,w1\n\t" /* Bit write complement of status bit Z to the bit in w4. 
                                               The position is indicated by four lsb of w1. w4,w1 have
                                               0x08FE,0x1105 respectively. After execution w4 has 0x08DE. */
            "btg w0,#9\n\t" /* Bit toggle 10th bit in w0. So w0 will have 0x0B04 after execution. */
            "btst.lC w0,#9\n\t" /* Bit test 10th bit in w0 and the value is stored in
                                               C bit of SR. This doesn't alter the contents of w0.
                                               w0 has 0x0B04.So here C bit gets set. SR contains 0x0003 (Z,C = 1). */
            "bsw.c w1,w4\n\t" /* Bit write status bit C to the bit specified in w1.
                                               The position is indicated by four lsb of w4. 
                                               w4,w1 have 0x08DE,0x1105 respectively. After execution w1 will have 0x5105. */
            "btg _DIAG_CPU_TestRam+4,#6\n\t" /* Bit toggle 7th bit in file register 0x1102. 
                                               So 0x1102 will have 0xB248 after execution. */
            "btst.lC w0, w1\n\t" /* Bit test the specified bit in w0 and the value is
                                               stored in C bit of SR. The position is given by the
                                               four lsb of w1. This doesn't alter the contents of w0.
                                               Here C bit gets cleared. SR contains 0x0002 (Z=1). */
            "btst.lZ w1,#14\n\t" /* Bit test 15th bit in w1 and the complement is stored
                                               in Z bit of SR. This doesn't alter the contents of w1.
                                               w1 has 0x5105. So here Z bit gets cleared. SR contains 0x0000 (Z,C = 0). */

            "btst.lZ w1, w0\n\t" /* Bit test the specified bit in w1 and the complement
                                               of the result is stored in Z bit of SR. The position
                                               is given by the four lsb of w0. This doesn't alter the
                                               content of w1,w0. SR contains 0x0002 (Z = 1). */
            "btst.lC w4,#12\n\t" /* Bit test 13th bit in w4 and the result is stored in
                                               C bit of SR. This alters the contents of w4. w4 has
                                               0x18DE. Here C bit gets cleared since the 13th bit in
                                               w4 is 0. SR contains 0x0002 (C = 0). */
            "btst.l _DIAG_CPU_TestRam,#10\n\t" /* Bit test 11th bit in file register 0x1104 and the
                                               complement is stored in Z bit of SR. This alters the
                                               content of 0x1104. 0x1104 has 0x00FE since 11th bit is
                                               set. So here Z bit gets cleared as 11th bit in 0x1104
                                               is one.SR contains 0x0002 (Z = 1). */
            "add w0,w2,w0\n\t"
            "add w6,w0,w0\n\t"
            "btst.lZ w1,#13\n\t" /* Bit test 14th bit in w1 and the complement is stored
                                               in Z bit of SR. This alters the content of w1. w1 has
                                               0x7105 after execution. So here Z bit gets set since
                                               the 14th bit in w1 is 0. SR contains 0x0002 (Z = 1). */
            "fbcl w4,w2\n\t" /* First bit change from MSB is stored in w2. The result is sign extended. */

            "ff1r w4,w3\n\t" /* First occurrence of 1 from right is checked for w4
                                               and stored in w3 with sign extension. */
            "xor w2,w3,w5\n\t" /* XOR w2 with w3 and store the result in w5. This is
                                               done to get a unique 16 bit result. Here two 16 bit
                                               results are 'xor'ed to produce one 16 bit value. */
            "ff1l w5,w2\n\t" /* First occurrence of 1 from left is checked for w5 and
                                               stored in w2 with sign extension. */

            /*..............................................................................
             Bit compare and skip instructions
            ..............................................................................*/

            "btst.b _DIAG_CPU_TestRam+4,#1\n\t" /* Bit test 2nd bit in file reg 0x1102 and skip the next
                                               instruction if set. The value is so chosen that the 
                                               next instruction gets executed. */
            "btst.b _DIAG_CPU_TestRam+4,#3\n\t" /* Bit test 4th bit in file reg 0x1102 and skip the next
                                               instruction if set. The value is so chosen that the
                                               next instruction gets skipped. So file register 0x1102 is not cleared. */
            "clr _DIAG_CPU_TestRam+4\n\t"

            "btst.b _DIAG_CPU_TestRam+4,#6\n\t" /* Bit test 7th bit in file reg 0x1102 and skip the next
                                               instruction if cleared. The value is so chosen that
                                               the next instruction gets executed. */
            "btst.b _DIAG_CPU_TestRam+4,#1\n\t" /* Bit test 2nd bit in file reg 0x1102 and skip the next
                                               instruction if cleared. The value is so chosen that
                                               the next instruction gets skipped. So file register
                                               0x1102 is not cleared. */
            "clr _DIAG_CPU_TestRam+4\n\t"

            "btst.lC w4,#11\n\t" /* Bit test 12th bit in w4, skip the next instruction
                                               if cleared. The value is so chosen that the next
                                               instruction gets executed. */
            "btst.bC w4,#5\n\t" /* Bit test 6th bit in w4 and skip the next instruction
                                               if cleared. The value is so chosen that the next
                                               instruction gets skipped. So w4 is not cleared. */
            //                      "clr w4\n\t"

            "btst.lC w4,#10\n\t" /* Bit test 11th bit in w4 and skip the next
                                               instruction if set. The value is so chosen that the
                                               next instruction gets executed. */
            "btst.bC w4,#7\n\t" /* Bit test 8th bit in w4 and skip the next instruction
                                               if set. The value is so chosen that the next
                                               instruction gets skipped. So w4 is not cleared. */
            "xor w2,w3,w3\n\t"
            "movif.l Z, w4,w2,w3\n\t"
            "movr [w4],[++w4]\n\t"

            /*..............................................................................
             The result is available in w0,w1,w4,w5,0x1102,0x1104. So to consolidate the
             result into one 16 bit value we use XOR and ADD instructions. The final
             result will be available in w0.
            ..............................................................................*/

            "xor.l _DIAG_CPU_TestRam+4,wreg\n\t"
            "xor _DIAG_CPU_TestRam+8,wreg\n\t"
            "xor.l _DIAG_CPU_TestRam,wreg\n\t"
            "xor.l w1,w6,w3\n\t"
            "xor.l w3,w2,w5\n\t"
            "xor w5,w7,w4\n\t"
            "add.l w4,w0,w1\n\t"
            "mov _DIAG_CPU_TestRam,w2\n\t"
            "sub.l w1,w2,w2\n\t"
            "mov _DIAG_CPU_TestRam+8,w3\n\t"
            "sub w1,w2,w2\n\t"
            "swap.l w2\n\t"
            "bset w2,#0\n\t"
            "mov.w w2,w1\n\t"
            "mov.l w1,_DIAG_CPU_TestResult\n\t"

            "pop w7\n\t"
            "pop w6\n\t"
            "pop w5\n\t"
            "pop w4\n\t"
            "pop w3\n\t"
            "pop w2\n\t"
            "pop w1\n\t"
            "pop w0\n\t"
            );

    subset1Res = (uint8_t) (DIAG_CPU_TestResult & DIAG_CPU_RESULT_BITMASK);
    if (subset1Res == DIAG_CPU_SELFTEST_SUB1_RESULT) {
        DIAG_CPU_SetRetValue(DIAG_PASS);
    } else {
        DIAG_CPU_SetRetValue(DIAG_FAIL);
    }
    result = DIAG_CPU_GetRetValue();
    return result;
    /*LDRA_EXCLUDE 88 S <justification start> functionally implemented to test assembly instruction behavior, hence violation ignored <justification end> */
}

/*LDRA_EXCLUDE 76 D <justification start>Function called as function pointer, wrongly reported by tool, violation ignored <justification end> */
/*LDRA_EXCLUDE 61 D <justification start>Tool reporting wrongly to declare as static because of above, violation ignored <justification end> */
uint32_t DIAG_CPU_SelfTest_Subset2(void) {
    uint32_t result;
    uint8_t subset2Res;
    __asm__ volatile ("push w0\n\t"
            "push w1\n\t"
            "push w2\n\t"
            "push w3\n\t"
            "push w4\n\t"
            "push w5\n\t"
            "push w6\n\t"
            "push w7\n\t"

            "push    CORCON\n\t"
            "push    w8\n\t"
            "push    w9\n\t"
            "push    w10\n\t"
            "push    w11\n\t"
            "push    w12\n\t"
            "push    w13\n\t"
            // "push    w14\n\t"

            /* Start with default state of CORCON register */
            "mov #0x0020, w0\n\t"
            "mov w0, CORCON\n\t"

            /* ..............................................................................
             Write data to the Data memory through X Bus:
             1. The values 0x5555, 0xAAAA, 0x0001, 0xFFFF, 0x1AAA, 0x1554, 0x3000, 0x47FE
                are written to the registers w10, w11, w1, w4, w12, w13, w14 and w8
                respectively depending on the data memory sizes.
             2. The values 0x5555, 0x5554 are written to data memory locations 0x1AAA and
                0x1554 irrespective of data memory size. Byte writes to data memory are
                also performed.
             3. The value 0x0001 is written to the second data memory location.
             4. The value 0xFFFF is written to the third data memory location.
             5. The locations in the data memory are selected such that all the possible
                bits of buses(XAGU-R/W, X-R/W) are toggled, irrespective of memory sizes
             6. The values which are written to Data memory locations are read and
                added/subtracted to the w0.
             7. Write to w0, w1, w4, w8, w10, w11, w12, w13 and w14 are performed.
             8. Read from w0, w1, w4, w8, w10, w12, w13 and w14 are performed.
             .............................................................................. */

            "mov.l     #_DIAG_CPU_Test2Data3, w10\n\t"
            "mov.l     #_DIAG_CPU_Test2Data4, w11\n\t"
            "mov     #_DIAG_CPU_Test2Data5, w1\n\t"
            "mov     #_DIAG_CPU_Test2Data6, w4\n\t"

            "mov     #_DIAG_CPU_TestRam1, w12\n\t"
            "mov     #_DIAG_CPU_TestRam2, w13\n\t"
            "mov     #_DIAG_CPU_TestRam3, w6\n\t"
            "mov     #_DIAG_CPU_TestRam4, w8\n\t"

            "mov.b   w13, [w13++]\n\t"
            "mov.l     w10, [w12]\n\t"
            "mov.b   w13, [w13--]\n\t"
            "mov.l     w1, [w6]\n\t"
            "mov.l     w4, [w8]\n\t"

            "add.l     w0, [w12], w0\n\t"
            "add.l     w0, [w13], w0\n\t"
            "add.l     w0, [w6], w0\n\t" /* 0x3000 is added to w0 */
            "sub.l     w0, [w8], w0\n\t" /* 0x47FE contents added to w0 */

            /* ..............................................................................
             RAW dependency checking:
             1. 0xFFFF is written to the location 0x1102.
             2. w10=0x5555, w11=0xAAAA which are added and written to the location 0x1100.
                The w9 is post incremented.
             3. The data memory location 0x1102 is read to w14 which is added to w0.
             4. If CPU has not introduced stall then w11=0x1100 location value is read,
                which will affect the result.
             5. The RAW dependency is checked with the Destination addressing mode
                (Indirect with modification)using w9, Source addressing mode(Indirect).
             6. Write to w0, w9, and w14 are performed.
             7. Read from w0, w4, w9, w10, w11 and w14 are performed.
             .............................................................................. */

            "mov.l     #_DIAG_CPU_TestRam, w9\n\t"
            //"mov.l     w3, _DIAG_CPU_TestRam+4\n\t" /* 0xAAAA is written to the location 0x1102 */ 
            "mov.l     w11, _DIAG_CPU_TestRam+4\n\t" //ASH Modified 
            "add.l     w10, w11, [w9++]\n\t" /* 0xFFFF is written to the location 0x1100 post-increment w9 */
            "mov.l     [w9], w6\n\t" /* 0xAAAA is moved to w14 RAW dependency. CPU stall will occur. */
            "sub.l     w0, w6, w0\n\t"

            /* ..............................................................................
             1. Testing of NOP and NOPR instructions.
             2. PCL and PCH are captured before and after executing NOP and NOPR. If these
                instructions fails to increment the PC then the result will be affected.
             3. Inorder to get result independent of PCL and PCH, PCH and PCL are
                subtracted first and later added to w0 during the testing of NOP and NOPR
             .............................................................................. */

            "mov.l     PC, w9\n\t"
            "sub.l     w0, w9, w0\n\t"
            "nop\n\t"
            "nopr\n\t"
            "add.l     PC, WREG\n\t"
            "mov.l     w0, _DIAG_CPU_TestRam3\n\t"
            "mov.l    w0, _DIAG_CPU_TestRam4\n\t"
            "mov.l #_DIAG_CPU_Test2Data3,w1\n\t"
            "sub.l w1,w0,w0\n\t"
            "mov #_DIAG_CPU_Test2Data6,w1\n\t"
            "sub.l w0,w1,w0\n\t"
            "mov #_DIAG_CPU_Test2Data1,w1\n\t"
            "sub w1,w0,w0\n\t"
            "swap w0\n\t"
            "mov #33365,w1\n\t"
            "sub w0,w1,w0\n\t"
            "mov.b     w0, _DIAG_CPU_TestResult\n\t"

            "pop     w13\n\t"
            "pop     w12\n\t"
            "pop     w11\n\t"
            "pop     w10\n\t"
            "pop     w9\n\t"
            "pop     w8\n\t"
            "pop     CORCON\n\t"

            "pop w7\n\t"
            "pop w6\n\t"
            "pop w5\n\t"
            "pop w4\n\t"
            "pop w3\n\t"
            "pop w2\n\t"
            "pop w1\n\t"
            "pop w0\n\t"
            );

    subset2Res = (uint8_t) (DIAG_CPU_TestResult & DIAG_CPU_RESULT_BITMASK);
    if (subset2Res == DIAG_CPU_SELFTEST_SUB2_RESULT) {
        DIAG_CPU_SetRetValue(DIAG_PASS);
    } else {
        DIAG_CPU_SetRetValue(DIAG_FAIL);
    }
    result = DIAG_CPU_GetRetValue();
    return result;
    /*LDRA_EXCLUDE 88 S <justification start> functionally implemented to test assembly instruction behavior, hence violation ignored <justification end> */
}

/*LDRA_EXCLUDE 76 D <justification start>Function called as function pointer, wrongly reported by tool, violation ignored <justification end> */
/*LDRA_EXCLUDE 61 D <justification start>Tool reporting wrongly to declare as static because of above, violation ignored <justification end> */
uint32_t DIAG_CPU_SelfTest_Subset3(void) {
    volatile uint32_t result;
    uint8_t subset3Res;

    __asm__ volatile ("push w0\n\t"
            "push w1\n\t"
            "push w2\n\t"
            "push w3\n\t"
            "push w4\n\t"
            "push w5\n\t"
            "push w6\n\t"
            "push w7\n\t"

            "push INTCON1\n\t"

            /*Now clear INTCON1 and WREG*/
            "clr INTCON1\n\t"
            "clr w0\n\t"
            "bset INTCON1, #15\n\t" //Enable the global interrupt
            "bset IEC0, #6\n\t" //Enable NVM interrupt
            "disictl #_DIAG_CPU_Test3Data25\n\t" //Disable all interrupts below level 7
            "bset IFS0, #6\n\t" //Set the NVM interrupt bit, it should not go to ISR because of DISI

            "mov.l #_DIAG_CPU_Test3Data2, w1\n\t"
            "mov.l #_DIAG_CPU_Test3Data26, w2\n\t"
            "mov.l #_DIAG_CPU_Test3Data3, w3\n\t"

            "bra     L_UNCONDITIONAL_3\n\t" /* Branch Unconditionally,
                                                     skips if branch succeeds */
            "add     w0, #_DIAG_CPU_Test3Data4, w0\n\t"
            "L_UNCONDITIONAL_3: bra w2\n\t"
            /* Computed branch
             w3=0x0003, so PC=(PC+2)+(2*w3)->PC,
             PC goes to L_COMPUTED_BRANCH_3
             skips if branch succeeds */
            "add     #_DIAG_CPU_Test3Data5, w0\n\t"
            /* If branch on false condition fails
             the program flow is moved to the END3
             to avoid infinite loop in branch. */
            "L_FALSE_3: add     #_DIAG_CPU_Test3Data6, w0\n\t"
            "bra     END_3\n\t"
            "L_COMPUTED_BRANCH_3: bclr    IFS0, #6\n\t" /* clear the interrupt */
            "bclr    IEC0, #6\n\t" /* disable the interrupt */
            "bclr    INTCON1, #15\n\t" /* Restore Global Interrupt disable state */

            "bra     GE, L_GE_3\n\t" /* branch if greater than or equal
                                                     skips if branch succeeds */
            "add     #_DIAG_CPU_Test3Data7, w0\n\t"
            "L_GE_3: bra     GTU, L_FALSE_3\n\t" /* branch if unsigned greater than */
            "bra     LTU, L_LTU_3\n\t" /* branch if unsigned less than
                                                     skips if branch succeeds */
            "add     #_DIAG_CPU_Test3Data8, w0\n\t"
            "L_LTU_3: bra     LE, L_FALSE_3\n\t" /* branch if less than */
            "bra     NOV, L_NOV_3\n\t" /* branch if not Overflow,
                                                     skips if branch succeeds */
            "add     #_DIAG_CPU_Test3Data9, w0\n\t"
            "L_NOV_3: bra     OV, L_FALSE_3\n\t" /* branch if Overflow */
            "bra     NZ, L_NZ_3\n\t" /* branch if not Zero,
                                                     skips if branch succeeds */
            "add     #_DIAG_CPU_Test3Data10, w0\n\t"
            "L_NZ_3: bra     Z, L_FALSE_3\n\t" /* branch if Zero */


            "dec.b   w1, w1\n\t" /* DC=1, N=1, OV=0, Z=0, C=1 */
            "bra     C, L_C_3\n\t" /* branch if carry,
                                                     skips if branch succeeds */
            "add     #_DIAG_CPU_Test3Data11, w0\n\t"
            "L_C_3:  bra     NC, L_FALSE_3\n\t" /* branch if not carry */
            "bra     GEU, L_GEU_3\n\t" /* branch if Unsigned greater than or equal,
                                                       skips if branch succeeds */
            "add     #_DIAG_CPU_Test3Data12, w0\n\t"
            "L_GEU_3: bra     GT, L_FALSE_3\n\t" /* branch if greater than */
            "bra     LT, L_LT_3\n\t" /* branch if less than */
            "add     #_DIAG_CPU_Test3Data13, w0\n\t" /* skips if branch succeeds */
            "L_LT_3: bra     LEU, L_FALSE_3\n\t" /* branch if unsigned less than or equal */
            "bra     N, L_N_3\n\t" /* branch if negative, 
                                                     skips if branch succeeds */
            "add     #_DIAG_CPU_Test3Data14, w0\n\t"
            "L_N_3:  bra     NN, L_FALSE_3\n\t" /* branch if not negative */

            "mov     PC, w4\n\t" /* PCL is subtracted from w0 */
            "sub     w0, w4, w0\n\t"
            "goto    _THERE_1\n\t"
            /* skips if Unconditional jump succeeds */
            "add     #_DIAG_CPU_Test3Data15, w0\n\t"
            "_THERE_1: add     PC, WREG\n\t" /* PC is added to w0 */

            "rcall   _RCALL_1\n\t" /* Relative Call */
            "add     w5, w0, w0\n\t" /* The w5=0x57 is added to w0
                                                     Computed Relative Call
                                                     w3=0x0003,so PC=(PC+2)+(2*w3)->PC */
            "rcall   w3\n\t" /* PC goes to _RCALL_2 */
            "goto    _THERE_2\n\t" /* goto address directly to _THERE_2
                                                     skips if Unconditional indirect-jump succeeds */
            "add     #_DIAG_CPU_Test3Data16, w0\n\t"
            /* Modify the running 16-bit result. */
            "_RCALL_2: add     #_DIAG_CPU_Test3Data17, w0\n\t"
            "return\n\t" /* PC will return to the next instruction after rcall w3 */

            "_THERE_2: mov.l     PC, w4\n\t" /* PC is subtracted from w0*/
            "add.l w0, w4, w0\n\t"

            "push w0\n\t"
            "call    _CALL_1\n\t" /* PC will move to _CALL_1 */
            "call    _CALL_2\n\t" /* PC will move to _CALL_2 */
            "mov.l PC, w4\n\t"
            "pop w0\n\t"
            "sub.l w0,w4,w0\n\t"
            "bclr    IEC0, #6\n\t" /* Interrupt request JTAG is disabled */
            "mov.l #321,w3\n\t"
            "sub w0,w3,w0\n\t"
            "mov     w0, _DIAG_CPU_TestResult\n\t"

            /* Retrieving DISICNT, INTCON1, INTCON2 from the stack */
            "END_3:  pop INTCON1\n\t"

            "pop w7\n\t"
            "pop w6\n\t"
            "pop w5\n\t"
            "pop w4\n\t"
            "pop w3\n\t"
            "pop w2\n\t"
            "pop w1\n\t"
            "pop w0\n\t");

    subset3Res = (uint8_t) (DIAG_CPU_TestResult & DIAG_CPU_RESULT_BITMASK);
    if (subset3Res == DIAG_CPU_SELFTEST_SUB3_RESULT) {
        DIAG_CPU_SetRetValue(DIAG_PASS);
    } else {
        DIAG_CPU_SetRetValue(DIAG_FAIL);
    }
    result = DIAG_CPU_GetRetValue();
    return result;
    /*LDRA_EXCLUDE 88 S <justification start> functionally implemented to test assembly instruction behavior, hence violation ignored <justification end> */
}

/*LDRA_EXCLUDE 76 D <justification start>Function called as function pointer, wrongly reported by tool, violation ignored <justification end> */
/*LDRA_EXCLUDE 61 D <justification start>Tool reporting wrongly to declare as static because of above, violation ignored <justification end> */
uint32_t DIAG_CPU_SelfTest_Subset4(void) {
    uint32_t result;
    uint8_t subset4Res;
    __asm__ volatile ("push w0\n\t"
            "push w1\n\t"
            "push w2\n\t"
            "push w3\n\t"
            "push w4\n\t"
            "push w5\n\t"
            "push w6\n\t"
            "push w7\n\t"

            /* Initially 0x1100 is loaded to W1. The data ram address 
               0x1100, W0 and W2 are made 0xFFFF using SETM instruction. */
            "clr w3\n\t"
            "mov #_DIAG_CPU_TestRam, w1\n\t"
            "setm _DIAG_CPU_TestRam\n\t"
            "setm.l w0\n\t"
            "setm W2\n\t"

            /* AND block */
            "and #_DIAG_CPU_Test4Data1, W2\n\t"
            "and.b w2, #_DIAG_CPU_Test4Data2,w3\n\t"
            "and W0, W3, [++W1]\n\t"
            "and1.l w0,#1,w0\n\t"
            "xor _DIAG_CPU_TestRam + 4\n\t"
            "sl _DIAG_CPU_TestRam + 4\n\t"
            "and _DIAG_CPU_TestRam + 4, WREG\n\t"

            /* IOR block */
            "clr _DIAG_CPU_TestRam + 4\n\t"
            "ior _DIAG_CPU_TestRam + 4\n\t"
            "sl.l  _DIAG_CPU_TestRam + 4, WREG\n\t"
            "ior _DIAG_CPU_TestRam + 4, WREG\n\t"
            "ior.b #_DIAG_CPU_Test4Data3, W0\n\t"
            "ior.l W0, W1, w4\n\t"
            "ior W4, #_DIAG_CPU_Test4Data4, W3\n\t"

            /* XOR block */
            "clr  w0\n\t"
            "xor #_DIAG_CPU_Test4Data1, W0\n\t"
            "xor.l W0, #_DIAG_CPU_Test4Data5, W4\n\t"
            "and _DIAG_CPU_TestRam\n\t"
            "xor _DIAG_CPU_TestRam , WREG\n\t"
            "xor W0, W4, [W1]\n\t"
            /* W1 contains 0x1102. This value is written to RAM address
               0x1102, which is used in the next instruction. */

            /* ROTATE block */
            "rrc _DIAG_CPU_TestRam + 4\n\t"
            "rrc.l _DIAG_CPU_TestRam + 4, WREG\n\t"
            "rrc w0, [w1]\n\t"
            /* W1 contains 0x1102. This value is written to RAM address 
               0x1102, which is used in the next instruction. */

            "rrnc _DIAG_CPU_TestRam + 4\n\t"
            "rrnc.l _DIAG_CPU_TestRam + 4, WREG\n\t"
            "rrnc w0, [w1]\n\t"

            "rlc _DIAG_CPU_TestRam + 4\n\t"
            "rlc.l _DIAG_CPU_TestRam + 4, WREG\n\t"
            "rlc w0, [w1]\n\t"

            "rlnc.l _DIAG_CPU_TestRam + 4\n\t"
            "rlnc _DIAG_CPU_TestRam + 4, WREG\n\t"
            "rlnc w0, w5\n\t"
            "mov.l w0,w1\n\t"
            "asrm.l w1,#1,w1\n\t"
            "mov.l w1,w0\n\t"


            /* COM block */
            "com.l _DIAG_CPU_TestRam +4\n\t"
            "com.l _DIAG_CPU_TestRam +4, WREG\n\t"
            "com.l W0, W1\n\t"

            /* NEG block */
            "neg.l _DIAG_CPU_TestRam + 4\n\t"
            "neg.l _DIAG_CPU_TestRam + 4, WREG\n\t"
            "neg.l w0, w1\n\t"

            /* SHIFT block */
            "lsr _DIAG_CPU_TestRam + 4\n\t"
            "lsr _DIAG_CPU_TestRam + 4, WREG\n\t"
            "lsr.l W0, W6\n\t"
            "asr.l W5, #7, W7\n\t"
            "asr W6, W7, W2\n\t"

            "asr _DIAG_CPU_TestRam + 4\n\t"
            "asr _DIAG_CPU_TestRam + 4, WREG\n\t"
            "asr W0, W6\n\t"
            "sl w6, #3, w7\n\t"
            "sl w7, w6\n\t"
            "lsr W6, #13, W7\n\t"
            "lsr W5, W7, W6\n\t"
            "lsr W6, #4, W5\n\t"
            "sl w2, w5, w0\n\t"

            "clr  W5\n\t"

            /* COMPARE block */
            "cp.b w1, w7\n\t"
            "cp _DIAG_CPU_TestRam + 4\n\t"
            "bra N, L_LOG_4\n\t" /* Here OV=1, so no branch occurs */
            "bra Z, L_LOG_4\n\t"
            "cpb.b w7, #_DIAG_CPU_Test4Data6\n\t"
            "bra NN, L_LOG_4\n\t"
            "mov #_DIAG_CPU_Test4Data10,w0\n\t"
            "mov w0,_DIAG_CPU_TestRam\n\t"
            "mov.l #_DIAG_CPU_Test4Data11,w0\n\t"
            "cpb _DIAG_CPU_TestRam\n\t"
            /* After the execution of this instruction, SR register contains all zeros. */
            "bra NOV, L_LOG_4\n\t"

            "cp0.l w5\n\t"
            "bra NZ, L_LOG_4\n\t"
            "mov w0,w2\n\t"
            "cp w2, #_DIAG_CPU_Test4Data7\n\t"
            "bra NC, L_LOG_4\n\t"
            "cpb w1, w5\n\t"

            /* Byte instructions */
            "sl.b w2, w3\n\t"
            "xor.b #_DIAG_CPU_Test4Data9, w3\n\t"
            "neg.b w3, w4\n\t"
            "lsr.b w4, w5\n\t"
            "com.b w5, w6\n\t"
            "sub.l w6,w4,w6\n\t"
            "xor w4,w5,w5\n\t"
            "mov.b w5,w6\n\t"
            /* This instruction complements W5 and stores the final result in W6. */

            "L_LOG_4: mov w6, _DIAG_CPU_TestResult\n\t"

            "pop w7\n\t"
            "pop w6\n\t"
            "pop w5\n\t"
            "pop w4\n\t"
            "pop w3\n\t"
            "pop w2\n\t"
            "pop w1\n\t"
            "pop w0\n\t");

    subset4Res = (uint8_t) (DIAG_CPU_TestResult & DIAG_CPU_RESULT_BITMASK);
    if (subset4Res == DIAG_CPU_SELFTEST_SUB4_RESULT) {
        DIAG_CPU_SetRetValue(DIAG_PASS);
    } else {
        DIAG_CPU_SetRetValue(DIAG_FAIL);
    }
    result = DIAG_CPU_GetRetValue();
    return result;
    /*LDRA_EXCLUDE 88 S <justification start> functionally implemented to test assembly instruction behavior, hence violation ignored <justification end> */
}

/*LDRA_EXCLUDE 76 D <justification start>Function called as function pointer, wrongly reported by tool, violation ignored <justification end> */
/*LDRA_EXCLUDE 61 D <justification start>Tool reporting wrongly to declare as static because of above, violation ignored <justification end> */
uint32_t DIAG_CPU_SelfTest_Subset5(void) {
    uint32_t result;
    uint8_t subset5Res;
    __asm__ volatile ("push w0\n\t"
            "push w1\n\t"
            "push w2\n\t"
            "push w3\n\t"
            "push w4\n\t"
            "push w5\n\t"
            "push w6\n\t"
            "push w7\n\t"
            "push w10\n\t"  /* FIX Issue#2: w10 is clobbered below — must be saved */

            /* This is done to make the test case independent of previous SR status values.
             To capture the SR values it is 'xor'ed with wreg.
             Here first SR is cleared.So whenever SR values are 'xor'with wreg
             it is 'and'ed with w7 to nullify the affect of previous SR values. */
            "mov     #0x010F, w7\n\t"

            "clr     _DIAG_CPU_TestRam2\n\t" /* To clear the previous content of 0x1554 */
            "setm.b  _DIAG_CPU_TestRam2\n\t" /* 0x1554<7:0> = #0xff. */
            "inc.l     _DIAG_CPU_TestRam2\n\t" /* 0x1554 = 0x1554 + #1 */
            "clr     w0\n\t" /* w0 is cleared before byte instruction to
                                                        clear the previous value in upper byte. */
            "inc.b   _DIAG_CPU_TestRam2, wreg\n\t" /* wreg<7:0> = 0x1554 + #1 */
            "inc     w0, w1\n\t" /* w1 = w0 + #1 */
            "inc2.b  _DIAG_CPU_TestRam2\n\t" /* 0x1554<7:0> = 0x1554 + #2 */
            "inc2    _DIAG_CPU_TestRam2, wreg\n\t" /* wreg = 0x1554 + #2 */
            "inc2    w1, w2\n\t" /* w2 = w1 + #2 */
            "add.l     _DIAG_CPU_TestRam2\n\t" /* 0x1554 = 0x1554 + wreg */
            "add     _DIAG_CPU_TestRam2, wreg\n\t" /* wreg = 0x1554 + wreg */
            "add     #_DIAG_CPU_Test5Data1, w2\n\t" /* w2 = w2 + #0x3ff */
            
            "and     w0, w7, w0\n\t" /* to nullify past SR value (from main application) */

            "add     w2, #_DIAG_CPU_Test5Data2, w3\n\t" /* w3 = w2 + #0x1f */
            "rlc.b   w2, w1\n\t" /* Rotate Left with Carry in byte mode.C = 0 here */
            "add.b   w3, w1, w4\n\t" /* w4<7:0> = w3 + w1 */
            "se      w4, w5\n\t" /* Move w4<7:0> to w5<7:0> and sign extend w5<15:8>. */
            "bra     LTU, L_FALSE_5\n\t" /* Branch if (!c). So here no branch takes place */
            "bra     GTU, L_GTU_5\n\t" /* Branch if (c&&!z). Here branch occurs. */
            "L_FALSE_5: mov     #_DIAG_CPU_Test5Data3, w2\n\t" /* If any branch instructions fails then it will
                                                                   branch here i.e L_FALSE. Here the value 0x1234
                                                                   is written into W0 register.
                                                                   So this affects the expected 16 bit result. */
            "bra     L_LOG_5\n\t"
            "L_GTU_5: addc    _DIAG_CPU_TestRam2\n\t" /* 0x1554 = 0x1554 + wreg + (C). C = 1 here */
            "bra     C, L_FALSE_5\n\t" /* branch if (C).Here branch doesn't occur. */
            "addc    #_DIAG_CPU_Test5Data2, w5\n\t" /* w5 = w5 + #0x3ff + (C). C = 0 here. */
            "dec.b   _DIAG_CPU_TestRam2\n\t" /* 0x1554<7:0> = 0x1554 - #1.decrement by one */
            "addc    w5, #_DIAG_CPU_Test5Data2, w6\n\t" /* w6 = w5 + #0x1f + (C). C = 1 here. */
            "asr.b   w6, w1\n\t" /* Arithmetic Shift Right in byte mode */
            "rrnc.b  w1, w6\n\t" /* Rotate Right with No Carry in byte mode.(C=1). */
            "addc.l    _DIAG_CPU_TestRam2, w0\n\t" /* wreg = 0x1554 + wreg + (C).carry bit is 1 here */
            "bra     LEU,L_LEU_5\n\t" /* branch if (!C||Z).Here branch occurs. */
            "bra     L_FALSE_5\n\t"

            "L_LEU_5: dec     w6, w2\n\t" /* w2 = w6 - #1 */
            "addc.b  w0, w2, w1\n\t" /* w1<7:0> = w0 + w2 + (C). Carry bit is 1 here. */
            "bra     GEU, L_FALSE_5\n\t" /* branch if (C).Here branch doesn't occur. */
            "bra     GE, L_FALSE_5\n\t" /* branch if ((N&&OV)||(!N&&!OV)). Here branch doesn't occur. */
            //                      "xor     SR, w0\n\t"             /* to store the contents of status register. */
            "and.l     w0, w7, w0\n\t" /* to nullify past value(from main application) of SR */
            "bra     N, L_FALSE_5\n\t" /* branch if (N).Here branch doesn't occur */
            "bra     LT, L_FALSE_5\n\t" /* branch if ((N&&!OV)||(!N&&OV)). Here branch doesn't occur. */
            "bra     NN, L_NN_5\n\t" /* branch if (!N).Here branch occurs */
            "bra     L_FALSE_5\n\t"

            "L_NN_5: dec2.b  _DIAG_CPU_TestRam2\n\t" /* 0x1554<7:0> = 0x1554 - #2 */
            "dec2    _DIAG_CPU_TestRam2, wreg\n\t" /* wreg = 0x1554 - #2 */
            "dec2    w1, w2\n\t" /* w2 = w1 - #2 */
            "rlnc.b  w0, w3\n\t" /* Rotate Left with No Carry in byte mode.(C = 1) */
            "rrc.b   w3, w0\n\t" /* Rotate Right with Carry in byte mode.C=1 here. */
            "sub.l     _DIAG_CPU_TestRam2\n\t" /* 0x1554 = 0x1554 - wreg */
            "bra     LE, L_LE_5\n\t" /* branch if (Z||(N&&!OV)||(!N&&OV)). Here branch occurs. */
            "bra     L_FALSE_5\n\t"

            "L_LE_5: sub.b   _DIAG_CPU_TestRam2, wreg\n\t" /* wreg<7:0>  = 0x1554 - wreg */
            "sub.l     #_DIAG_CPU_Test5Data1, w2\n\t" /* w2 = w2 - #0x3ff */
            "sub     w2, #_DIAG_CPU_Test5Data2, w3\n\t" /* w3 = w2 - #0x1f */
            "subb.l    _DIAG_CPU_TestRam2\n\t" /* 0x1554 = 0x1554 - wreg - (!C). C = 1 here. */
            "subb    _DIAG_CPU_TestRam2, wreg\n\t" /* wreg = 0x1554 - wreg - (!C). C = 1 here. */
            "ze      w0, w4\n\t" /* move w0<7:0> to w4<7:0> and zero extend w4<15:8>. */
            "bra     GT, L_GT_5\n\t" /* branch if ((!Z&&N&&OV)||(!Z&&!N&&!OV)).
                                                        Here, the branch is taken. */
            "bra     L_FALSE_5\n\t"

            "L_GT_5: subb    #_DIAG_CPU_Test5Data1, w4\n\t" /* w4 = w4 - #0x3ff - (!C). C = 1 here. */
            "dec     _DIAG_CPU_TestRam2, wreg\n\t" /* wreg = 0x1554 - #1 */
            "subb   w5, w3, w1\n\t"
            "subb    w4, #_DIAG_CPU_Test5Data2, w5\n\t" /* w5 = w4 - #0x1f - (!C). C = 1 here. */
            /* w1<7:0> = w5 - w3 - (!C). C = 1 here. */
            "bra     C, L_NC_5\n\t" /* branch if C. Here branch occurs. */
            "bra     L_FALSE_5\n\t"

            "L_NC_5: subbr.b _DIAG_CPU_TestRam2\n\t" /* 0x1554<7:0> = wreg - 0x1554 - (!C). C = 0 here. */
            "subbr   _DIAG_CPU_TestRam2, wreg\n\t" /* wreg = wreg - 0x1554 - (!C). C = 0 here. */
            "subbr   w1, #_DIAG_CPU_Test5Data2, w3\n\t" /* w3 = #0x1f - w1 - (!C). C = 0 here. */
            "clr.b   w0\n\t" /* w0<7:0> = 0x00.Used to cover CLR in byte mode. */
            "subr    _DIAG_CPU_TestRam2\n\t" /* 0x1554 = wreg - 0x1554 */
            "subr    _DIAG_CPU_TestRam2, wreg\n\t" /* wreg = wreg - 0x1554 */
            "subr    w0, #_DIAG_CPU_Test5Data2, w2\n\t" /* w2 = #0x1f - w0 */
            "subbr   w3, w2, w4\n\t" /* w4 = w2 - w3 - (!c). C = 0 here */
            "subr.b  w6, w7, w5\n\t" /* w5<7:0> = w7 - w6. */

            /* Divide unsigned double word */
            "repeat #5\n\t"
            "divu.l w4, w2\n\t"

            "bra     OV, L_FALSE_5\n\t" /* branch if (!OV). Here branch doesn't occur. */
            "mov.l #_DIAG_CPU_Test5Data4,w10\n\t"
            "add.l w10,w2,w2\n\t"
            "add.l w2,w6,w2\n\t"
            "mov.l #_DIAG_CPU_Test5Data5,w6\n\t"
            "repeat #9\n\t"
            "divul w2,w6\n\t"
            "bra     NOV, L_OV_5\n\t" /* branch if (OV). Here branch occurs. */
            "bra     L_FALSE_5\n\t"

            "L_OV_5: sub     w0, w1, w1\n\t"
            "xor.l w1,w2,w2\n\t"
            "xor.l w5,w2,w2\n\t"
            "and w2,w5,w2\n\t"
            "and w2,w3,w2\n\t"
            "L_LOG_5: mov.b    w2, _DIAG_CPU_TestResult\n\t" /* writing the result to W0. */

            "pop w10\n\t"  /* FIX Issue#2: restore w10 */
            "pop w7\n\t"
            "pop w6\n\t"
            "pop w5\n\t"
            "pop w4\n\t"
            "pop w3\n\t"
            "pop w2\n\t"
            "pop w1\n\t"
            "pop w0\n\t");

    subset5Res = (uint8_t) (DIAG_CPU_TestResult & DIAG_CPU_RESULT_BITMASK);
    if (subset5Res == DIAG_CPU_SELFTEST_SUB5_RESULT) {
        DIAG_CPU_SetRetValue(DIAG_PASS);
    } else {
        DIAG_CPU_SetRetValue(DIAG_FAIL);
    }
    result = DIAG_CPU_GetRetValue();
    return result;
    /*LDRA_EXCLUDE 88 S <justification start> functionally implemented to test assembly instruction behavior, hence violation ignored <justification end> */
}

/*LDRA_EXCLUDE 76 D <justification start>Function called as function pointer, wrongly reported by tool, violation ignored <justification end> */
/*LDRA_EXCLUDE 61 D <justification start>Tool reporting wrongly to declare as static because of above, violation ignored <justification end> */
uint32_t DIAG_CPU_SelfTest_Subset6(void) {
    volatile uint32_t result = 0;
    uint8_t subset6Res;

    __asm__ volatile ("push w0\n\t"
            "push w1\n\t"
            "push w2\n\t"
            "push w3\n\t"
            "push w4\n\t"
            "push w5\n\t"
            "push w6\n\t"
            "push w7\n\t"
            "push w8\n\t"

            /* .............................................................................
             Saving of SFR's INTCON1, INTCON2, RCOUNT, CORCON on to the stack.
             ............................................................................. */
            "push    INTCON1\n\t"
            "push    INTCON2\n\t"
            "push    RCOUNT\n\t"
            "push    CORCON\n\t"
            "bset    w1,#2\n\t"
            "clr     w5\n\t"

            /* Start with default state of INTCON1 and INTCON2 registers */
            "clr     INTCON1\n\t"
            
            /* .............................................................................
             1. Move 0xF042 to w0 and store the value 0xF042 into the data memory
                at the location 0x1AAA.
             2. mov the address 0xAAA to w3 and 0x8001 to w4.
             3. Multiply the contents w4 with the contents of [w3] and store the result
                to w6:w7. Both source operands and the result are interpreted as two's
                complement signed numbers. Register indirect addressing is used for second
                operand.
             4. Unsigned integer divide is performed. The result of previous mul.ss
                instruction is used as i/p values for this division. The 16-bit quotient
                of the divide operation is stored in W0, and the 16-bit remainder is
                stored in W1 by default. The result of this division will be used as i/p of
                other multiplication or division. This cycle continues so that the
                end result will validate all the features tested.
             5. Multiply the contents of w0 with the contents of w1, and store the 32-bit
                result w6.
             ............................................................................. */

            "mov     #_DIAG_CPU_Test6Data1, w0\n\t" /* 0xF042 is moved to w0 */
            "mov     w0, _DIAG_CPU_TestRam1\n\t" /* 0xF042 is stored at 0x0AAA */
            "mov     #_DIAG_CPU_TestRam1, w3\n\t" /* 0x0AAA is moved to w3 */
            "mov     #_DIAG_CPU_Test6Data2, w4\n\t" /* 0x8001 is moved to w4 */

            "mulss.l  w4, [w3], w6\n\t"       /* Integer 16x16-bit Signed Multiply */

            "repeat  #5\n\t" /* Unsigned 16/16-bit integer divide */
            "divul   w6, w4\n\t"

            "mov w0,w8\n\t" "mulsu.l  w0, w1, w6\n\t" /* Integer 16x16-bit Signed-Unsigned Multiply */

            "mov w0,w8\n\t"
            /* .............................................................................
             1. Generate the divide by zero math error trap using div.s instruction
                with the operands as w6 and w5.
             2. Tested interrupt call and return operations.
             3. In the math error trap ISR the RCOUNT is cleared so that effectively next
                instruction after the div.s instruction will be executed.
             4. The w1:w0 are of no use after the divide by zero error.
             ............................................................................. */

            "repeat  #5\n\t" /* divide by zero arithmetic error trap generation */
            "divs   w6, w5\n\t"

            "mov w0,w8\n\t"
            /* .............................................................................
             1. Multiply the contents of w4 with unsigned short literal 0x07 and store the
                result to w2:w3.
             2. Signed 16/16-bit integer divide is performed once again to check whether
                division operation can recovered after the math error trap or not.
             3. Multiply the contents of w0 with w1 and store the result to w6:w7.
             4. Signed 32/16-bit integer divide is performed. The 16-bit quotient of the
                divide operation is stored in W0, and the 16-bit remainder is stored
                in W1 by default.
             5. Multiply the contents of w0 with the contents of w1 and store the result
                to w6:w7.
             6. Multiply the contents of w6 with the 5-bit literal 0x1F and store the
                result to w2:w3.
             7. w2, w3 validates above operations. w5 validates operations in math trap ISR
             8. w2, w3, w5 and w7 are added and stored to produce the final result in w0.
             ............................................................................. */

            /* Integer 16x16-bit Signed-Unsigned Literal Multiply */
            "muluu.l  w6, #_DIAG_CPU_Test6Data3, w2\n\t"

            "mov w0,w8\n\t"
            "repeat  #5\n\t" /* Signed 16/16-bit integer divide */
            "divs   w2, w4\n\t"

            "mov w0,w8\n\t"
            "mulus  w0, w1, w6\n\t" /* Integer 16x16-bit Unsigned-Signed Multiply */

            "mov     #_DIAG_CPU_Test6Data6, w3\n\t" /* mov #5 (0x05) to w4 */
            "repeat  w3\n\t" /* Signed 32/16-bit integer divide */
            "divs.l  w6, w3\n\t"

            "mov w0,w8\n\t"
            "muluu  w0, w1, w1\n\t" /* Integer 16x16-bit Unsigned-Unsigned
                                                      Short Literal Multiply */
            "muluu.l  w6, #_DIAG_CPU_Test6Data4, w2\n\t"

            "add.l     w2, w3, w2\n\t"
            "add.l     w2, w7, w0\n\t"
            "add.l w0,w1,w0\n\t"

            "mov w0,w8\n\t"
            "mov _DIAG_CPU_TestResult, w1\n\t" /* Add results from Math Error Trap */
            "add.l  w0, w1, w0\n\t"
            "xor w1,w0,w0\n\t"
            "sub.l w7,w6,w5\n\t"
            "sub.l w5,w0,w0\n\t"
            "xor w0,w3,w0\n\t"
            "and.l w0,w3,w0\n\t"
            "bset w0,#1\n\t"
            "mov.l  w0, _DIAG_CPU_TestResult\n\t"


            /* Retrieving of SFR's INTCON1, INTCON2, RCOUNT, CORCON from the stack. */
            "pop     CORCON\n\t"
            "pop     RCOUNT\n\t"
            "pop     INTCON2\n\t"
            "pop     INTCON1\n\t"

            "pop w8\n\t"
            "pop w7\n\t"
            "pop w6\n\t"
            "pop w5\n\t"
            "pop w4\n\t"
            "pop w3\n\t"
            "pop w2\n\t"
            "pop w1\n\t"
            "pop w0\n\t");

    subset6Res = (uint8_t) (DIAG_CPU_TestResult & DIAG_CPU_RESULT_BITMASK);
    if (subset6Res == DIAG_CPU_SELFTEST_SUB6_RESULT) {
        DIAG_CPU_SetRetValue(DIAG_PASS);
    } else {
        DIAG_CPU_SetRetValue(DIAG_FAIL);
    }
    result = DIAG_CPU_GetRetValue();
    return result;
    /*LDRA_EXCLUDE 88 S <justification start> functionally implemented to test assembly instruction behavior, hence violation ignored <justification end> */
}

/*LDRA_EXCLUDE 76 D <justification start>Function called as function pointer, wrongly reported by tool, violation ignored <justification end> */
/*LDRA_EXCLUDE 61 D <justification start>Tool reporting wrongly to declare as static because of above, violation ignored <justification end> */
/* LDRA_EXCLUDE 65 D <justification start>Wrapper function used to wrap the assembly instructions. Violation Ignored.<justification end> */
void DIAG_CPU_MathError(void) {
    __asm__ volatile ("btst.b INTCON4, #0\n\t"
            /* Check if the math error trap is caused by divide by zero or by accumulator overflow. */
            /* If DIV0ERR = 1, then branch to execute TestSubset_6 specific code, else execute TestSubset_7 specific code. */
            "bra NZ,TestSubset_6MathISR\n\t"

            /* The following code is specific to Test Subset 7 */
            "TestSubset_7MathISR: inc _DIAG_CPU_TestResult\n\t" /* Increment count of trap occurrences */
            "bra MathErrorTrapReturn\n\t"

            /* The following code is specific to Test Subset 6 */
            "TestSubset_6MathISR: mov.l #_DIAG_CPU_Test6Data5, w5\n\t"
            "add.l w0,w5,w5\n\t"
            "mov   SR, w0\n\t" /* IPL<2:0> and RA bits are captured in W0 */
            "mul.b RCOUNT\n\t" /* validating RCOUNT by multiplying with W0 */
            "clr   RCOUNT\n\t"
            "add.l w0,w5,w0\n\t"
            "mov   w0, _DIAG_CPU_TestResult\n\t" /* Save W0 value for test-subset code */
            "bclr INTCON4, #0\n\t" /* Clear the DIV0ERR bit */

            "MathErrorTrapReturn: bclr INTCON4, #5\n\t" /* Clear OVAERR */
            "bclr INTCON4, #4\n\t" /* Clear OVBERR */
            "bclr INTCON4, #3\n\t" /* Clear COVAERR */
            "bclr INTCON4, #2\n\t" /* Clear COVBERR */
            "bclr INTCON4, #1\n\t"); /* Clear SFTACERR */
}

/*LDRA_EXCLUDE 76 D <justification start>Function called as function pointer, wrongly reported by tool, violation ignored <justification end> */
/*LDRA_EXCLUDE 61 D <justification start>Tool reporting wrongly to declare as static because of above, violation ignored <justification end> */
uint32_t DIAG_CPU_SelfTest_Subset7(void) {
    uint32_t result;
    uint8_t subset7Res;


    __asm__ volatile ("push w0\n\t"
            "push w1\n\t"
            "push w2\n\t"
            "push w3\n\t"
            "push w4\n\t"
            "push w5\n\t"
            "push w6\n\t"
            "push w7\n\t"

            /* Saving of w8-w13, INTCON1, INTCON2, CORCON and DO loop control registers on to the stack */
            "push    w8\n\t"
            "push    w10\n\t"
            "push    w11\n\t"
            "push    w12\n\t"
            "push    w13\n\t"
            "push    INTCON1\n\t"
            "push    INTCON2\n\t"
            "push    INTCON4\n\t"
            "push    CORCON\n\t"

            /* Start with default state of INTCON1 and INTCON2 registers */
            //                      "clr     INTCON4\n\t"

            /* Start with default state of CORCON register */
            "mov #0x0020, w0\n\t"
            "mov w0, CORCON\n\t"

            "clr _DIAG_CPU_TestResult\n\t"

            "mov.l #0x00300000, w0\n\t" /* INTCON1 settings are moved to w0 */
            "ior.l INTCON4\n\t" /* Acc A overflow trap,Acc B overflow trap and catastrophic 
                                               Acc overflow trap enabled (OVATE,OVBTE,COVTE bits set) */

            /* The toggling of Y address bus is done by choosing the Y address location such
            a way that all bits are toggled.The X address location 0x110C is loaded to w8
            to use it for MAC prefetch operations. */
            "mov #_DIAG_CPU_TestRam + 0xC, w8\n\t"
            "mov #_DIAG_CPU_TestRamY1, w10\n\t"
            "mov #_DIAG_CPU_TestRamY2, w11\n\t"

            /* Here the used address locations are loaded with values. */
            "mov w11, [w8]\n\t"
            "mov w10, [w11]\n\t"
            "mov w8, [w10]\n\t"

            /* Here Acc A is cleared first and then loaded with value in w8 shifted by 8 to
            its left. This causes Acc overflow into guard bits A<39:32>. Math Error trap
            occurs due to Acc A overflow. Here both OVAERR and MATHERR bits get set. */
            "clr A\n\t"
            "clr B\n\t"

            "push w8\n\t"
            "mov #0xA00C, w8\n\t"     /* Load value with bit 15 set to ensure Acc A overflow */
            "lac w8, #-8, A\n\t" /* This causes arithmetic trap due to Acc A overflow */
            "pop w8\n\t"               /* Restore pointer value */
            "bclr.b INTCON4+2, #5\n\t" /* Clear OVATE bit (bit 21 of INTCON4 = bit 5 of byte at INTCON4+2) */
            "bra OA, L_OA_7\n\t"
            "bra L_FALSE_7\n\t"

            /* If any of the branch conditions fail the program control comes here. 0x1234
            is loaded into result variable and branch to L_LOG where the result register
            is compared with the expected value */
            "L_FALSE_7: mov #_DIAG_CPU_Test7Data1, w1\n\t"
            //                      "bra L_LOG_7\n\t"
            /* Control comes here when branch on overflow of Acc A occurs */
            "L_OA_7: mov #0x10E3, w3\n\t"
            "mov w3, CORCON\n\t" /* Unsigned,Acc A saturation,Acc B saturation,Data Space Write saturation,
                                              Normal Acc saturation mode,Biased rounding,Integer mode */
            "mov w11, w13\n\t"
            "mov.l [w8],w4\n\t"

            "add.l w4,#_DIAG_CPU_Test7Data2,w4\n\t"
            "mac w4,w4, A, w2\n\t"
            "bra OA, L_FALSE_7\n\t"

            "mov.l #_DIAG_CPU_Test7Data3, w6\n\t"

            "mac w4,w6, A, w2\n\t"//...

            "L_SA_7: sac A, #-8, [w8]\n\t"
            "bclr CORCON, #5\n\t" /* Data space write saturation disabled (SATDW = 0) */

            "mac w4,w4, B, w3\n\t"//..
            /* Here, biased rounding mode is set. So 1 is added to 
             Acc A<31:16> and stored in AWB (Accumulator Write Back). */
            "sac.r B, #7, [w8]\n\t" /* Here, since Acc B<15:0> < 0x8000, the Acc B is
//                                             rounded down (add nothing)and written to AWB. */
            "neg B\n\t"
            "sub B\n\t"
            "mov.l #_DIAG_CPU_Test7Data4,w2\n\t"
            "add.l w2,w3,w3\n\t"
            "sub w10, w11, w12\n\t"
            "mov.l #_DIAG_CPU_Test7Data3,w7\n\t"
            "mov.l w3,w5\n\t"
            "mpy w5,w7, A, w2\n\t"
            "add A\n\t"
            "mov.l w3,w6\n\t"

            "edac.l w6,w6, B, w3\n\t"
            "bclr CORCON, #7\n\t" /* Clear SATA bit */
            "bclr CORCON, #6\n\t" /* Clear SATB bit */

            /* This causes Acc overflow into guard bits A<39:32> and catasrophic overflow as
             the sign bit B<39> gets destroyed. Math Error trap occurs due to Acc B overflow
             and Acc B catastrophic overflow. So OVBERR,COVBERR and MATHERR bits get set. */
            "sftac B, #-9\n\t" /* shift value is chosen that it will saturate Acc B to 0x8000000000. */
            "bclr.b INTCON4+2, #4\n\t" /* Clear OVBTE bit (bit 20 of INTCON4 = bit 4 of byte at INTCON4+2) */
            "bra SB, L_SB_7\n\t"

            "L_SB_7: mov #0x00F0, w2\n\t"
            "mov w2, CORCON\n\t" /* Signed,Acc A saturation,Acc B saturation,Data Space Write saturation,
                                              Acc super saturation mode,Unbiased rounding,fractional mode. */
            "ed   w2,w3, A, w2\n\t"
            "add.l w0,w3,w0\n\t"

            /* Arithmetic trap occurs due to Acc shift error. So SFTAERR, MATHERR bits get set. */
            "sftac A, w6\n\t"
            "mov w0,w8\n\t"
            "add.l w0,w3,w0\n\t"
            "slm.l w6,#4,w6\n\t"
            "llac.l w6,#10,A\n\t"
            "luac w6,#5,B\n\t"
            "sacr.w A,#3,w3\n\t"
            "add.l w0,w3,w0\n\t"
            "sqrsc w5,A,w2\n\t"
            "min A\n\t"
            "add.l w2,w3,w2\n\t"
            "add.l w0,w2,w0\n\t"
            "min w6,w3\n\t"
            "sqr w3,A,w3\n\t"
            "add.l w3,w0,w3\n\t"
            "sqrac w3,B,w3\n\t"
            "max B\n\t"
            "max w6,w5\n\t"
            "norm B,w6\n\t"
            "norm.l A,w5\n\t"
            "suac A,#3,w3\n\t"
            "sqrn w3,A,w3\n\t"

            "add.l w2,w3,w3\n\t"
            "mov w3,w7\n\t"
            "mpyn w7,w7,A,w3\n\t"
            "msc w7,w7, B, w2\n\t"
            "add.l w2,w3,w3\n\t"
            "and w6, w7, w7\n\t"

            "mpy w6,w7, A,w2\n\t"
            "add w2, #4, A\n\t"
            "sac A, #0, w4\n\t"

            "xor w4, w6, w3\n\t"
            "xor w3, w7, w4\n\t"
            "add.l w0, w4, w0\n\t"

            "xor.l w0, w3, w1\n\t"
            "xor.l w1,w8,w1\n\t"

            "L_LOG_7: mov _DIAG_CPU_TestResult, w0\n\t" /* Add results from Math Error Trap */
            "add w0, w1, w0\n\t"
            "bset w1,#1\n\t"
            "xor w0,w1,w0\n\t"
            "bset w0,#0\n\t"
            "mov w0, _DIAG_CPU_TestResult\n\t"


            /* Restoring the previous values */
            "pop    CORCON\n\t"
            "pop    INTCON4\n\t"
            "pop    INTCON2\n\t"
            "pop    INTCON1\n\t"
            "pop    w13\n\t"
            "pop    w12\n\t"
            "pop    w11\n\t"
            "pop    w10\n\t"
            "pop    w8\n\t"

            "pop w7\n\t"
            "pop w6\n\t"
            "pop w5\n\t"
            "pop w4\n\t"
            "pop w3\n\t"
            "pop w2\n\t"
            "pop w1\n\t"
            "pop w0\n\t");

    subset7Res = (uint8_t) (DIAG_CPU_TestResult & DIAG_CPU_RESULT_BITMASK);
    if (subset7Res == DIAG_CPU_SELFTEST_SUB7_RESULT) {
        DIAG_CPU_SetRetValue(DIAG_PASS);
    } else {
        DIAG_CPU_SetRetValue(DIAG_FAIL);
    }
    result = DIAG_CPU_GetRetValue();
    return result;
    /*LDRA_EXCLUDE 88 S <justification start> functionally implemented to test assembly instruction behavior, hence violation ignored <justification end> */
}

/*LDRA_EXCLUDE 76 D <justification start>Function called as function pointer, wrongly reported by tool, violation ignored <justification end> */
/*LDRA_EXCLUDE 61 D <justification start>Tool reporting wrongly to declare as static because of above, violation ignored <justification end> */
uint32_t DIAG_CPU_SelfTest_Subset8(void) {
    uint32_t result;
    uint8_t subset8Res;

    __asm__ volatile ("push w0\n\t"
            "push w1\n\t"
            "push w2\n\t"
            "push w3\n\t"
            "push w4\n\t"
            "push w5\n\t"
            "push w6\n\t"
            "push w7\n\t"

            /* Saving of SFR's w8,w10,DSRPAG,DCOUNT,DOSTARTL,DOSTARTH,DOENDL,DOENDH,MODCON,XMODSRT,
                XMODEND,YMODSRT,YMODEND and XBREV on to the stack. */
            "push    w8\n\t"
            "push    w10\n\t"
            "push    RCOUNT\n\t"   /* FIX Issue#3: save modulo/bit-rev SFRs — were commented out */
            "push    MODCON\n\t"
            "push    XMODSRT\n\t"
            "push    XMODEND\n\t"
            "push    YMODSRT\n\t"
            "push    YMODEND\n\t"
            "push    XBREV\n\t"

            /* Start with default state of CORCON register */
            "mov #0x0020, w0\n\t"
            "mov w0, CORCON\n\t"

            /* ..............................................................................
             Writing data to Y memory locations:
             1. mov 0x273C to w0 and 0x7F54 to w1.
             2. Store the contents of w0 to Y memory.
             3. Store the contents of w1 to Y memory.
             .............................................................................. */

            "mov     #_DIAG_CPU_Test8Data1, w0\n\t"
            "mov     #_DIAG_CPU_Test8Data2, w1\n\t"

            "mov _DIAG_CPU_TestRamY2, w2\n\t"
            "add #0x2,w2\n\t"
            "mov _DIAG_CPU_TestRamY2, w10\n\t"
            "add #0x4,w10\n\t"
            "mov     w0, [w2]\n\t"
            "mov     w1, [w10]\n\t"

            /* ..............................................................................
              Modulo Addressing (X Data space, Incrementing, word):
             1. Modulo addressing with circular buffers supported by X data space.
             2. Modulo Addressing Initialization for Incrementing Modulo Buffers.
             3. The word sized modulo buffers are implemented.
             4. The Buffer length is 8 bytes.
             5. Buffer starting address is taken as 0x1100, which is loaded into XMODSRT.
             6. The Buffer end address is 0x1105, which is loaded into XMODEND.
             7. 0x8FF3 is loaded into MODCON where w3 is used to access the circular-
                buffers and set the XMODEN bit in MODCON.
             8. Testing of DO loop is also performed here. The DO loop control registers
                added/subtracted to w0 such that w0(result) is independent of PCL or PCH.
                These addition/subtraction will be done when the loop count is '0',
                that is at the last loop iteration. DCOUNT register is added to w0
                in each loop iteration. The testing of DA bit in SR register is also done.
             9. The values written to the data memory locations are shown below. If more
                than one value is shown across an address means, its the updated value
                which is because of circular buffers.
 
                address     Values(w1) written to data memory
                0x1100       0x7F54, 0x7F5A
                0x1102       0x7F56
                0x1104       0x7F58
             10. w3 register address will be adjusted to 0x1100 automatically
                at the end of the buffer.
             .............................................................................. */

            "mov     #_DIAG_CPU_TestRam, w3\n\t"
            "mov     w3, XMODSRT\n\t" /* 0x1100 is loaded into XMODSRT */
            "mov     #(_DIAG_CPU_TestRam + 0x5), w4\n\t"
            "mov     w4, XMODEND\n\t" /* 0x1105 is loaded into XMODEND */
            "mov     #_DIAG_CPU_Test8Data3, w5\n\t"
            "mov     w5, MODCON\n\t" /* 0x8FF3 is loaded into MODCON */

            "bra     LOOP\n\t" /* if DA=1 branch to LOOP */
            "sub     w0, w5, w0\n\t" /* such that w0 is independent of PCL or PCH */
            "sub     w0, w5, w0\n\t"
            "LOOP:   mov     w1, [w3++]\n\t" /* contents of w1 are written to data memory */
            "XMODULO: inc2    w1, w1\n\t" /* increment contents of w1 by 2 */

            /* ..............................................................................
             Modulo Addressing (X Data space, Decrementing, byte):
             1. Modulo addressing with circular buffers supported by X data space.
             2. Modulo Addressing Initialization for Decrementing Modulo Buffers.
             3. The byte sized modulo buffers are implemented.
             4. The Buffer length is 2 bytes.
             5. Buffer end address is taken as 0x1107, which is loaded into XMODEND.
             6. The Buffer starting address is 0x1106, which is loaded into XMODSRT.
             7. The contents of MODCON are not changed, where w3 is used to access the
                circular buffers.
             8. The values written to the data memory locations are shown below. If more
                than one value is shown across an address means, its the updated value
                which is because of circular buffers.
                The contents of [w2] are used for writing to data memory.
                address     Values[w2] written to data memory
                0x1106       0x27
                0x1107       0x3C, 0x54
                So the location 0x1106 contains 0x5427(word aligned)
             9. w3 register address will be adjusted to 0x1107 automatically
                at the end of the buffer.
             .............................................................................. */

            "mov     #(_DIAG_CPU_TestRam + 0x7), w3\n\t"
            "mov     w3, XMODEND\n\t" /* 0x1107 is loaded into XMODEND */
            "mov     #(_DIAG_CPU_TestRam + 0x6), w4\n\t"
            "mov     w4, XMODSRT\n\t" /* 0x1106 is loaded into XMODSRT */
            "repeat  #_DIAG_CPU_Test8Data9\n\t" /* repeat with a count of 0x2 */
            "mov.b   [w2++], [w3--]\n\t" /* at the end w3,w4=0x1106, w2=0xAAAF */

            /* ..............................................................................
             1. Move the value 0x1100 to w5.
             2. Store the contents of w5 to w8.
             3. Move the contents of data memory at the location 0x1100 to w6.
             4. The Accumulator A is cleared and the location 0x1102 contents are moved to
                w7. The contents of w6 and w7 are used as input operands for
                next mac instruction.
             5. Increment the w4 contents by 2. Now w4 becomes 0x1108.
             6. w4 will be used to access the Bit-reversed circular buffers and
                w8 will be used to read the X space data memory locations in the next
                mac instruction.
             .............................................................................. */

            "mov     #_DIAG_CPU_TestRam, w5\n\t" /* mov 0x1100 to w5 */
            "mov     w5, w8\n\t" /* move 0x1100 to w8, move 0x1100 contents to w6 */
            "mov     [w8++], w6\n\t" /* and post-increment w8.
                                                   Clear accumulator A, move 0x1102 contents to w7 and post-increment w8. */

            "add     #0xC, w4\n\t" /* w4 = TestRam+0x12 (non-overlapping with source at TestRam) */

            /* ..............................................................................
             Bit-Reversed Addressing (X Data space):
             1. 0x04FF is loaded into the MODCON, where w4 is used to access the
                bit-reverse addressed buffers.
             2. 0x8001 is loaded into the XBREV, which will set the BREN bit and loads the
                buffer modifier value as 0x1 (i.e Buffer size = 2 words).
             3. w5 contains 0x1100. The w4 contains 1108.
             4. w4 register address will be adjusted to 0x1108 automatically
                at the end of the buffer.
             5. The values written to the data memory locations are shown below. If more
                than one value is shown across an address means, its the updated value
                which is because of bit-reverse addressed buffers.
                address     Values written to data memory
                0x1108       7F5A, 7F58
                0x110A       7F56, 5427
             6. The locations 0x1100 and 0x1102 contents are already moved to w6 and w7.
                The locations 0x1104-0x110A will be read through the next mac instruction
                and modified, so that all the above features tested can be validated.
             .............................................................................. */

            "mov.l     #0x00000000, w3\n\t"
            "mov.l    w3, MODCON\n\t" /* Disable all modulo (MC106 fix: prevents bus stall) */
            "mov.l    w3, XBREV\n\t" /* Disable bit-reverse (MC106 fix) */
            "mov     #_DIAG_CPU_TestRam, w5\n\t" /* reload w5 = source base (MC106 fix) */
            "mov     #_DIAG_CPU_TestRam1, w4\n\t" /* w4 = TestRam1 at 0x48A0, non-overlapping (MC106 fix) */
            "repeat  #_DIAG_CPU_Test8Data8\n\t" /* repeat with a count of 0x5 */
            "mov     [w5++], [w4++]\n\t"

            /* ..............................................................................
             Modulo Addressing (Y Data space, Decrementing, Word):
             1. Modulo addressing with circular buffers supported by Y data space.
             2. Modulo Addressing Initialization for Decrementing Modulo Buffers.
             3. The word sized modulo buffers are implemented.
             4. The Buffer length is 4 bytes.
             5. The w2 contains the result (depending on the RAM_SIZE), which will
                be moved to YMODEND.
             6. 0xAC is moved to w2(byte operation) so that w2 contains
                the result (depending on the RAM_SIZE), which is loaded into YMODSRT.
             7. 0x4FAF is loaded into MODCON which will set YMODEN and w10 will be used
                to access the circular buffers.
             8. w10 register address will be adjusted automatically at the end of
                the buffer.
             9. 0x1104-0x110A will be read through the next mac instruction
                and modified, so that all the above features tested can be validated.
             10.The last read of w6 and w7 are used as operands for division instruction.
             11.Add ACCH to wreg.
             .............................................................................. */

            "mov     w2,YMODEND\n\t" /* load Y end address */
            "mov.b   #_DIAG_CPU_Test8Data6, w2\n\t" /* 0xAC is moved to lower byte of w2 */
            "mov     w2, YMODSRT\n\t" /* load Y start address */
            "mov     #_DIAG_CPU_Test8Data7, w3\n\t"
            "mov     w3, MODCON\n\t" /* 0x4FAF is loaded into MODCON */
            "mov [--w8],w7\n\t"
            "add.l w2,w3,w2\n\t"
            "mac     w6,w7, A, w3\n\t"
            "add     w0,A\n\t"

            /* ..............................................................................
             Testing DIVF instruction:
             1. mov running 16-bit result to w2 as w0 and w1 will be modified because of
                divf instruction.
             2. Signed 16/16-bit fractional divide is performed. The 16-bit quotient of the
                divide operation is stored in W0, and the 16-bit remainder is stored in W1.
             3. w0, w1, w2 are added and the final result is stored in w0.
             .............................................................................. */

            "mov     w0, w2\n\t"
            "repeat  #_DIAG_CPU_Test8Data8\n\t"
            "divf    w7, w6\n\t" /* Signed 16/16-bit fractional divide */

            "add     w1, w2, w1\n\t"
            "add     w1, w0, w0\n\t" /* The final 16-bit result written to w0 */
            "add.l w0,w2,w2\n\t"
            "bclr w2,#1\n\t"
            "mov.b w2,w3\n\t"
            "mov.b     w3, _DIAG_CPU_TestResult\n\t"
            "mov _DIAG_CPU_TestResult,w0\n\t"

            "pop     XBREV\n\t"   /* FIX Issue#3: restore modulo/bit-rev SFRs */
            "pop     YMODEND\n\t"
            "pop     YMODSRT\n\t"
            "pop     XMODEND\n\t"
            "pop     XMODSRT\n\t"
            "pop     MODCON\n\t"
            "pop     RCOUNT\n\t"
            "pop     w10\n\t"
            "pop     w8\n\t"

            "pop w7\n\t"
            "pop w6\n\t"
            "pop w5\n\t"
            "pop w4\n\t"
            "pop w3\n\t"
            "pop w2\n\t"
            "pop w1\n\t"
            "pop w0\n\t");

    subset8Res = (uint8_t) (DIAG_CPU_TestResult & DIAG_CPU_RESULT_BITMASK);
    if (subset8Res == DIAG_CPU_SELFTEST_SUB8_RESULT) {
        DIAG_CPU_SetRetValue(DIAG_PASS);
    } else {
        DIAG_CPU_SetRetValue(DIAG_FAIL);
    }
    result = DIAG_CPU_GetRetValue();
    return result;
    /*LDRA_EXCLUDE 88 S <justification start> functionally implemented to test assembly instruction behavior, hence violation ignored <justification end> */
}
/*LDRA_ANALYSIS*/
