/**
 *  @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_sram_ecc_event.c
 *  @version         1.0
 *  @brief           This file has the implementation for the SRAM ecc diagnostics
 *  @see             diag_sram.h
 *************************************************************************/
/*Function headers*/
#include "diag_sram.h"
#include "diag_sram_shared.h"

static volatile uint32_t sramSingleBitTestStatus;

static volatile uint32_t sramDoubleBitErrorStatus;

static void DIAG_SRAM_HandleSingleBitError(uint32_t **faultAddress, uint8_t bitValue);

static void DIAG_SRAM_HandleDoubleBitError(uint32_t **faultAddress, uint8_t bitValue);

void DIAG_SRAM_SetSramDoubleBitTrapEntryStatus(uint32_t status)
{
    sramDoubleBitErrorStatus = status;
}

void DIAG_SRAM_SetSramSingleBitIsrEntryStatus(uint32_t status)
{
    sramSingleBitTestStatus = status;
}

static void DIAG_SRAM_HandleSingleBitError(uint32_t **faultAddress, uint8_t bitValue)
{
    volatile uint32_t *sramSingleBitErrorIePtr;
    volatile uint32_t sramintrBitMask;
    uint32_t timeOut = 0U;
    volatile uint32_t dummyRead;
    volatile uint32_t sramBaseAddress;
    uint32_t addrOffset;
    uint32_t baseAddress;
/*Since there could be original data at the location where the fault is injected, 
  the backup is taken and restored after the test is performed*/    
    volatile uint32_t origDataBackUp;
    volatile uint32_t fltAddrVal;
    
    origDataBackUp = **faultAddress;
	/* LDRA_EXCLUDE 439 S <justification start>The value of the address is required. Violation Ignored.<justification end> */
    fltAddrVal = (uint32_t)*faultAddress;
    sramSingleBitTestStatus = DIAG_SRAM_SINGLE_BIT_ERROR_ISR_WAITING;
    **faultAddress = DIAG_SRAM_SAMPLE_FAULT_DATA;
    sramintrBitMask = (fltAddrVal < DIAG_SRAM_XMEM_BOUNDARY_ADDR) ? (DIAG_SRAM_X_MEM_ECC_INTR_FLAG_MASK) : (DIAG_SRAM_Y_MEM_ECC_INTR_FLAG_MASK);
    /* LDRA_EXCLUDE 439 S <justification start>Wrong Violation reported by the tool. Violation Ignored.<justification end> */
	sramBaseAddress = (volatile uint32_t)((fltAddrVal < DIAG_SRAM_XMEM_BOUNDARY_ADDR) ? (DIAG_SRAM_XMEM_REG_BASE_ADDR) : (DIAG_SRAM_YMEM_REG_BASE_ADDR));
	/* LDRA_EXCLUDE 606 S <justification start>Wrong Violation reported by the tool. Violation Ignored.<justification end> */
    /* LDRA_EXCLUDE 440 S <justification start>Wrong violation reported by the tool. Violation Ignored.<justification end> */
    /* LDRA_EXCLUDE 45 D <justification start>Address ensured to be non null before assignment. Violation Ignored.<justification end> */
    sramMemoryAddr_t sramRegAddrPtr = (sramMemoryAddr_t)sramBaseAddress;
	/* LDRA_EXCLUDE 554 S <justification start>Casting required to access the literal as fixed memory address. Violation Ignored.<justification end> */
    sramSingleBitErrorIePtr = (volatile uint32_t *)DIAG_INTR_REQ_ENABLE_REG0;
    (*sramRegAddrPtr)[DIAG_SRAM_ECC_CONTROL_REG_INDEX] |= DIAG_SRAM_ECC_ENABLE_MASK;
    *sramSingleBitErrorIePtr |= sramintrBitMask;
    (*sramRegAddrPtr)[DIAG_SRAM_ECC_CONTROL_REG_INDEX] |= DIAG_SRAM_ECC_FLTINJ_ENABLE_MASK;
    baseAddress = (fltAddrVal < DIAG_SRAM_XMEM_BOUNDARY_ADDR) ? (uint32_t)(DIAG_SRAM_XMEM_START_ADDR) : (uint32_t)(DIAG_SRAM_YMEM_START_ADDR);
    addrOffset = fltAddrVal - baseAddress;
    (*sramRegAddrPtr)[DIAG_SRAM_FAULT_ADDRESS_INDEX] = addrOffset;
    (*sramRegAddrPtr)[DIAG_SRAM_FAULT_POINTER_INDEX] = DIAG_SRAM_SINGLE_BIT_FAULT_MASK;
    /* LDRA_EXCLUDE 45 D <justification start>Address ensured to be non null before assignment. Violation Ignored.<justification end> */
    (*sramRegAddrPtr)[DIAG_SRAM_FAULT_POINTER_INDEX] |= bitValue;
    /*Delay introduced to offset the Slow Clock speed SFR access. The clock is 
     4x slower, than the CPU, while accessing the ECC Fault Injection SFRs*/
    __builtin_repeat_nop(2U);
    
    dummyRead = **faultAddress;
/*The ldra annotation is necessary here because the diagnostic itself indicates injecting a failure and checking if the 
  failure has occurred. Unless there is an issue in the fault injection mechanism in the hardware, there is no way to simulate
  the failure condition in this scenario. ALthough we will be able to cover the PASS scenario, using the usual testing 
  mechanism, the tool has the limitation for the scope of annotation. Hence the whole check goes under the annotation*/
/*LDRA_NOANALYSIS*/ 
    //Wait for the interrupt flag for the Single bit error to be set
    while((sramSingleBitTestStatus == DIAG_SRAM_SINGLE_BIT_ERROR_ISR_WAITING) && (timeOut < DIAG_SRAM_INTERRUPT_SWITCH_TIMEOUT))
    {
        timeOut += 1U;
    }
   
    if(sramSingleBitTestStatus == DIAG_SRAM_SINGLE_BIT_ERROR_ISR_TRIGGERED)
    {
        DIAG_SRAM_SetRetValue(DIAG_PASS);
    }
    else
    {
        DIAG_SRAM_SetRetValue(DIAG_FAIL);
    }
/*LDRA_ANALYSIS*/    
    (*sramRegAddrPtr)[DIAG_SRAM_ECC_CONTROL_REG_INDEX] &= ~DIAG_SRAM_ECC_FLTINJ_ENABLE_MASK;
    //dummy read
    sramSingleBitTestStatus = dummyRead;
    //Restore the data in the original location
    **faultAddress = origDataBackUp;
}

static void DIAG_SRAM_HandleDoubleBitError(uint32_t **faultAddress, uint8_t bitValue)
{
    uint32_t timeOut = 0U;
    volatile uint32_t dummyRead;
    volatile uint32_t sramBaseAddress;
    volatile uint32_t addrOffset;
    volatile uint32_t baseAddress;
/*Since there could be original data at the location where the fault is injected, 
  the backup is taken and restored after the test is performed*/     
    volatile uint32_t dataBackup;
    volatile uint32_t dblFltAddrVal;
        
    dataBackup = **faultAddress;
	/* LDRA_EXCLUDE 439 S <justification start>The value of the address is required. Violation Ignored.<justification end> */
    dblFltAddrVal = (uint32_t)*faultAddress;
    sramDoubleBitErrorStatus = DIAG_SRAM_DOUBLE_BIT_TRAP_WAITING;
    
    **faultAddress = DIAG_SRAM_SAMPLE_FAULT_DATA;
    /* LDRA_EXCLUDE 439 S <justification start>Wrong Violation reported by the tool. Violation Ignored.<justification end> */
	sramBaseAddress = (volatile uint32_t)((dblFltAddrVal < DIAG_SRAM_XMEM_BOUNDARY_ADDR) ? (DIAG_SRAM_XMEM_REG_BASE_ADDR) : (DIAG_SRAM_YMEM_REG_BASE_ADDR));
	/* LDRA_EXCLUDE 606 S <justification start>Wrong Violation reported by the tool. Violation Ignored.<justification end> */
    /* LDRA_EXCLUDE 440 S <justification start>Wrong violation reported by the tool. Violation Ignored.<justification end> */
    sramMemoryAddr_t sramRegAddrPtr = (sramMemoryAddr_t)sramBaseAddress;
    (*sramRegAddrPtr)[DIAG_SRAM_ECC_CONTROL_REG_INDEX] |= (DIAG_SRAM_ECC_ENABLE_MASK|DIAG_SRAM_ECC_FLTINJ_ENABLE_MASK);
    baseAddress = (dblFltAddrVal < DIAG_SRAM_XMEM_BOUNDARY_ADDR) ? (uint32_t)(DIAG_SRAM_XMEM_START_ADDR) : (uint32_t)(DIAG_SRAM_YMEM_START_ADDR);
	/* LDRA_EXCLUDE 134 S <justification start>Base Address computation depends on variable address. Violation Ignored.<justification end> */
    addrOffset = dblFltAddrVal - baseAddress;
    (*sramRegAddrPtr)[DIAG_SRAM_FAULT_ADDRESS_INDEX] = addrOffset;
    (*sramRegAddrPtr)[DIAG_SRAM_FAULT_POINTER_INDEX] = (uint32_t)(bitValue) << 8U;
    (*sramRegAddrPtr)[DIAG_SRAM_FAULT_POINTER_INDEX] |= (bitValue + 1U);
    /*Delay introduced to offset the Slow Clock speed SFR access. The clock is 
     4x slower, than the CPU, while accessing the ECC Fault Injection SFRs*/
    __builtin_repeat_nop(2U);
    
    dummyRead = **faultAddress;
    //Wait for the interrupt flag for the Single bit error to be set
/*The ldra annotation is necessary here because the diagnostic itself indicates injecting a failure and checking if the 
  failure has occurred. Unless there is an issue in the fault injection mechanism in the hardware, there is no way to simulate
  the failure condition in this scenario. ALthough we will be able to cover the PASS scenario, using the usual testing 
  mechanism, the tool has the limitation for the scope of annotation. Hence the whole check goes under the annotation*/    
/*LDRA_NOANALYSIS*/    
    while((sramDoubleBitErrorStatus == DIAG_SRAM_DOUBLE_BIT_TRAP_WAITING) && (timeOut < DIAG_SRAM_INTERRUPT_SWITCH_TIMEOUT))
    {
        timeOut += 1U;
    }
    if(sramDoubleBitErrorStatus == DIAG_SRAM_DOUBLE_BIT_TRAP_ENTERED)
    {
        DIAG_SRAM_SetRetValue(DIAG_PASS);
    }
    else
    {
        DIAG_SRAM_SetRetValue(DIAG_FAIL);
    }
/*LDRA_ANALYSIS*/    
    (*sramRegAddrPtr)[DIAG_SRAM_ECC_CONTROL_REG_INDEX] &= ~DIAG_SRAM_ECC_FLTINJ_ENABLE_MASK;
    **faultAddress = dataBackup;
    //dummy read
    sramDoubleBitErrorStatus = dummyRead;
}

uint32_t DIAG_SRAM_SingleDoubleErrorDetectionTest(uint8_t errorType,uint32_t *sramFaultAddressPtr, uint8_t faultBitValue)
{
    volatile uint32_t retVal;
    uint32_t **ptrToFaultAddress;
    ptrToFaultAddress = &sramFaultAddressPtr;
    void (*srameccEvent[DIAG_SRAM_ERROR_TYPES])(uint32_t **fltAddr,uint8_t faultBitValue) = {DIAG_SRAM_HandleSingleBitError,DIAG_SRAM_HandleDoubleBitError};
    
    if(faultBitValue > DIAG_SRAM_MAX_FAULT_BIT_VALUE)
    {
        DIAG_SRAM_SetRetValue(DIAG_INVALID_PARAM);
    }
    else
    {
        //Now handle the corresponding single bit or double bit error
        (*srameccEvent[errorType])(ptrToFaultAddress,faultBitValue);
    }
    retVal = DIAG_SRAM_GetRetValue();
    return(retVal);    
}


