557 lines
17 KiB
C
557 lines
17 KiB
C
![]() |
/******************************************************************************
|
||
|
*
|
||
|
* Copyright (C) 2011 - 2014 Xilinx, Inc. All rights reserved.
|
||
|
*
|
||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||
|
* of this software and associated documentation files (the "Software"), to deal
|
||
|
* in the Software without restriction, including without limitation the rights
|
||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||
|
* copies of the Software, and to permit persons to whom the Software is
|
||
|
* furnished to do so, subject to the following conditions:
|
||
|
*
|
||
|
* The above copyright notice and this permission notice shall be included in
|
||
|
* all copies or substantial portions of the Software.
|
||
|
*
|
||
|
* Use of the Software is limited solely to applications:
|
||
|
* (a) running on a Xilinx device, or
|
||
|
* (b) that interact with a Xilinx device through a bus or interconnect.
|
||
|
*
|
||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||
|
* XILINX CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
||
|
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||
|
* SOFTWARE.
|
||
|
*
|
||
|
* Except as contained in this notice, the name of the Xilinx shall not be used
|
||
|
* in advertising or otherwise to promote the sale, use or other dealings in
|
||
|
* this Software without prior written authorization from Xilinx.
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
/*****************************************************************************/
|
||
|
/**
|
||
|
* @file xbram_selftest.c
|
||
|
*
|
||
|
* The implementation of the XBram driver's self test function. This SelfTest
|
||
|
* is only applicable if ECC is enabled.
|
||
|
* If ECC is not enabled then this function will return XST_SUCCESS.
|
||
|
* See xbram.h for more information about the driver.
|
||
|
* Temp change
|
||
|
*
|
||
|
* @note
|
||
|
*
|
||
|
* None
|
||
|
*
|
||
|
* <pre>
|
||
|
* MODIFICATION HISTORY:
|
||
|
*
|
||
|
* Ver Who Date Changes
|
||
|
* ----- ---- -------- -----------------------------------------------
|
||
|
* 1.00a sa 11/24/10 First release
|
||
|
* 3.01a sa 01/13/12 Changed Selftest API from
|
||
|
* XBram_SelfTest(XBram *InstancePtr) to
|
||
|
* XBram_SelfTest(XBram *InstancePtr, u8 IntMask) and
|
||
|
* fixed a problem with interrupt generation for CR 639274
|
||
|
* Modified Selftest example to return XST_SUCCESS when
|
||
|
* ECC is not enabled and return XST_FAILURE when ECC is
|
||
|
* enabled and Control Base Address is zero (CR 636581)
|
||
|
* Modified Selftest to use correct CorrectableCounterBits
|
||
|
* for CR 635655
|
||
|
* Updated to check CorrectableFailingDataRegs in the case
|
||
|
* of LMB BRAM.
|
||
|
* 3.02a sa 04/16/12 Added test of byte and halfword read-modify-write
|
||
|
* 3.03a bss 05/22/13 Added Xil_DCacheFlushRange in InjectErrors API to
|
||
|
* flush the Cache after writing to BRAM (CR #719011)
|
||
|
* </pre>
|
||
|
*****************************************************************************/
|
||
|
|
||
|
/***************************** Include Files ********************************/
|
||
|
#include "xbram.h"
|
||
|
#include "xil_cache.h"
|
||
|
/************************** Constant Definitions ****************************/
|
||
|
#define TOTAL_BITS 39
|
||
|
|
||
|
/**************************** Type Definitions ******************************/
|
||
|
|
||
|
/***************** Macros (Inline Functions) Definitions ********************/
|
||
|
#define RD(reg) XBram_ReadReg(InstancePtr->Config.CtrlBaseAddress, \
|
||
|
XBRAM_ ## reg)
|
||
|
#define WR(reg, data) XBram_WriteReg(InstancePtr->Config.CtrlBaseAddress, \
|
||
|
XBRAM_ ## reg, data)
|
||
|
|
||
|
#define CHECK(reg, data, result) if (result!=XST_SUCCESS || RD(reg)!=data) \
|
||
|
result = XST_FAILURE;
|
||
|
|
||
|
/************************** Variable Definitions ****************************/
|
||
|
static u32 PrngResult;
|
||
|
|
||
|
/************************** Function Prototypes *****************************/
|
||
|
static inline u32 PrngData(u32 *PrngResult);
|
||
|
|
||
|
static inline u32 CalculateEcc(u32 Data);
|
||
|
|
||
|
static void InjectErrors(XBram * InstancePtr, u32 Addr,
|
||
|
int Index1, int Index2, int Width,
|
||
|
u32 *ActualData, u32 *ActualEcc);
|
||
|
|
||
|
|
||
|
/*****************************************************************************/
|
||
|
/**
|
||
|
* Generate a pseudo random number.
|
||
|
*
|
||
|
* @param The PrngResult is the previous random number in the pseudo
|
||
|
* random sequence, also knwon as the seed. It is modified to
|
||
|
* the calculated pseudo random number by the function.
|
||
|
*
|
||
|
* @return The generated pseudo random number
|
||
|
*
|
||
|
* @note None.
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
static inline u32 PrngData(u32 *PrngResult)
|
||
|
{
|
||
|
*PrngResult = *PrngResult * 0x77D15E25 + 0x3617C161;
|
||
|
return *PrngResult;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************************************************************/
|
||
|
/**
|
||
|
* Calculate ECC from Data.
|
||
|
*
|
||
|
* @param The Data Value
|
||
|
*
|
||
|
* @return The calculated ECC
|
||
|
*
|
||
|
* @note None.
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
static inline u32 CalculateEcc(u32 Data)
|
||
|
{
|
||
|
unsigned char c[7], d[32];
|
||
|
u32 Result = 0;
|
||
|
int Index;
|
||
|
|
||
|
for (Index = 0; Index < 32; Index++) {
|
||
|
d[31 - Index] = Data & 1;
|
||
|
Data = Data >> 1;
|
||
|
}
|
||
|
|
||
|
c[0] = d[0] ^ d[1] ^ d[3] ^ d[4] ^ d[6] ^ d[8] ^ d[10] ^ d[11] ^
|
||
|
d[13] ^ d[15] ^ d[17] ^ d[19] ^ d[21] ^ d[23] ^ d[25] ^ d[26] ^
|
||
|
d[28] ^ d[30];
|
||
|
|
||
|
c[1] = d[0] ^ d[2] ^ d[3] ^ d[5] ^ d[6] ^ d[9] ^ d[10] ^ d[12] ^
|
||
|
d[13] ^ d[16] ^ d[17] ^ d[20] ^ d[21] ^ d[24] ^ d[25] ^ d[27] ^
|
||
|
d[28] ^ d[31];
|
||
|
|
||
|
c[2] = d[1] ^ d[2] ^ d[3] ^ d[7] ^ d[8] ^ d[9] ^ d[10] ^ d[14] ^
|
||
|
d[15] ^ d[16] ^ d[17] ^ d[22] ^ d[23] ^ d[24] ^ d[25] ^ d[29] ^
|
||
|
d[30] ^ d[31];
|
||
|
|
||
|
c[3] = d[4] ^ d[5] ^ d[6] ^ d[7] ^ d[8] ^ d[9] ^ d[10] ^ d[18] ^
|
||
|
d[19] ^ d[20] ^ d[21] ^ d[22] ^ d[23] ^ d[24] ^ d[25];
|
||
|
|
||
|
c[4] = d[11] ^ d[12] ^ d[13] ^ d[14] ^ d[15] ^ d[16] ^ d[17] ^ d[18] ^
|
||
|
d[19] ^ d[20] ^ d[21] ^ d[22] ^ d[23] ^ d[24] ^ d[25];
|
||
|
|
||
|
c[5] = d[26] ^ d[27] ^ d[28] ^ d[29] ^ d[30] ^ d[31];
|
||
|
|
||
|
c[6] = d[0] ^ d[1] ^ d[2] ^ d[3] ^ d[4] ^ d[5] ^ d[6] ^ d[7] ^
|
||
|
d[8] ^ d[9] ^ d[10] ^ d[11] ^ d[12] ^ d[13] ^ d[14] ^ d[15] ^
|
||
|
d[16] ^ d[17] ^ d[18] ^ d[19] ^ d[20] ^ d[21] ^ d[22] ^ d[23] ^
|
||
|
d[24] ^ d[25] ^ d[26] ^ d[27] ^ d[28] ^ d[29] ^ d[30] ^ d[31] ^
|
||
|
c[5] ^ c[4] ^ c[3] ^ c[2] ^ c[1] ^ c[0];
|
||
|
|
||
|
for (Index = 0; Index < 7; Index++) {
|
||
|
Result = Result << 1;
|
||
|
Result |= c[Index] & 1;
|
||
|
}
|
||
|
|
||
|
return Result;
|
||
|
}
|
||
|
|
||
|
/*****************************************************************************/
|
||
|
/**
|
||
|
* Get the expected actual data read in case of uncorrectable errors.
|
||
|
*
|
||
|
* @param The injected data value including errors (if any)
|
||
|
* @param The syndrome (calculated ecc ^ actual ecc read)
|
||
|
*
|
||
|
* @return The actual data value read
|
||
|
*
|
||
|
* @note None.
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
static inline u32 UncorrectableData(u32 Data, u8 Syndrome)
|
||
|
{
|
||
|
switch (Syndrome) {
|
||
|
case 0x03: return Data ^ 0x00000034;
|
||
|
case 0x05: return Data ^ 0x001a2000;
|
||
|
case 0x09: return Data ^ 0x0d000000;
|
||
|
case 0x0d: return Data ^ 0x00001a00;
|
||
|
|
||
|
case 0x11: return Data ^ 0x60000000;
|
||
|
case 0x13: return Data ^ 0x00000003;
|
||
|
case 0x15: return Data ^ 0x00018000;
|
||
|
case 0x19: return Data ^ 0x00c00000;
|
||
|
case 0x1d: return Data ^ 0x00000180;
|
||
|
|
||
|
case 0x21: return Data ^ 0x80000000;
|
||
|
case 0x23: return Data ^ 0x00000008;
|
||
|
case 0x25: return Data ^ 0x00040000;
|
||
|
case 0x29: return Data ^ 0x02000000;
|
||
|
case 0x2d: return Data ^ 0x00000400;
|
||
|
|
||
|
case 0x31: return Data ^ 0x10000000;
|
||
|
case 0x35: return Data ^ 0x00004000;
|
||
|
case 0x39: return Data ^ 0x00200000;
|
||
|
case 0x3d: return Data ^ 0x00000040;
|
||
|
}
|
||
|
return Data;
|
||
|
}
|
||
|
|
||
|
/*****************************************************************************/
|
||
|
/**
|
||
|
* Inject errors using the hardware fault injection functionality, and write
|
||
|
* random data and read it back using the indicated location.
|
||
|
*
|
||
|
* @param InstancePtr is a pointer to the XBram instance to
|
||
|
* be worked on.
|
||
|
* @param The Addr is the indicated memory location to use
|
||
|
* @param The Index1 is the bit location of the first injected error
|
||
|
* @param The Index2 is the bit location of the second injected error
|
||
|
* @param The Width is the data byte width
|
||
|
* @param The ActualData is filled in with expected data for checking
|
||
|
* @param The ActualEcc is filled in with expected ECC for checking
|
||
|
*
|
||
|
* @return None
|
||
|
*
|
||
|
* @note None.
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
static void InjectErrors(XBram * InstancePtr, u32 Addr,
|
||
|
int Index1, int Index2, int Width,
|
||
|
u32 *ActualData, u32 *ActualEcc)
|
||
|
{
|
||
|
u32 InjectedData = 0;
|
||
|
u32 InjectedEcc = 0;
|
||
|
u32 RandomData = PrngData(&PrngResult);
|
||
|
|
||
|
if (Index1 < 32) {
|
||
|
InjectedData = 1 << Index1;
|
||
|
} else {
|
||
|
InjectedEcc = 1 << (Index1 - 32);
|
||
|
}
|
||
|
|
||
|
if (Index2 < 32) {
|
||
|
InjectedData |= (1 << Index2);
|
||
|
} else {
|
||
|
InjectedEcc |= 1 << (Index2 - 32);
|
||
|
}
|
||
|
|
||
|
WR(FI_D_0_OFFSET, InjectedData);
|
||
|
WR(FI_ECC_0_OFFSET, InjectedEcc);
|
||
|
|
||
|
XBram_Out32(Addr, RandomData);
|
||
|
Xil_DCacheFlushRange(Addr, 4);
|
||
|
switch (Width) {
|
||
|
case 1: /* Byte - Write to do Read-Modify-Write */
|
||
|
XBram_Out8(Addr, PrngData(&PrngResult) & 0xFF);
|
||
|
break;
|
||
|
case 2: /* Halfword - Write to do Read-Modify-Write */
|
||
|
XBram_Out16(Addr, PrngData(&PrngResult) & 0xFFFF);
|
||
|
break;
|
||
|
case 4: /* Word - Read */
|
||
|
(void) XBram_In32(Addr);
|
||
|
break;
|
||
|
}
|
||
|
*ActualData = InjectedData ^ RandomData;
|
||
|
*ActualEcc = InjectedEcc ^ CalculateEcc(RandomData);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*****************************************************************************/
|
||
|
/**
|
||
|
* Run a self-test on the driver/device. Unless fault injection is implemented
|
||
|
* in hardware, this function only does a minimal test in which available
|
||
|
* registers (if any) are written and read.
|
||
|
*
|
||
|
* With fault injection, all possible single-bit and double-bit errors are
|
||
|
* injected, and checked to the extent possible, given the implemented hardware.
|
||
|
*
|
||
|
* @param InstancePtr is a pointer to the XBram instance.
|
||
|
* @param IntMask is the interrupt mask to use. When testing
|
||
|
* with interrupts, this should be set to allow interrupt
|
||
|
* generation, otherwise it should be 0.
|
||
|
*
|
||
|
* @return
|
||
|
* - XST_SUCCESS if fault injection/detection is working properly OR
|
||
|
* if ECC is Not Enabled in the HW.
|
||
|
* - XST_FAILURE if the injected fault is not correctly detected or
|
||
|
* the Control Base Address is Zero when ECC is enabled.
|
||
|
* .
|
||
|
*
|
||
|
* If the BRAM device is not present in the
|
||
|
* hardware a bus error could be generated. Other indicators of a
|
||
|
* bus error, such as registers in bridges or buses, may be
|
||
|
* necessary to determine if this function caused a bus error.
|
||
|
*
|
||
|
* @note None.
|
||
|
*
|
||
|
******************************************************************************/
|
||
|
int XBram_SelfTest(XBram *InstancePtr, u8 IntMask)
|
||
|
{
|
||
|
Xil_AssertNonvoid(InstancePtr != NULL);
|
||
|
Xil_AssertNonvoid(InstancePtr->IsReady == XIL_COMPONENT_IS_READY);
|
||
|
|
||
|
|
||
|
|
||
|
if (InstancePtr->Config.EccPresent == 0) {
|
||
|
return (XST_SUCCESS);
|
||
|
}
|
||
|
|
||
|
if (InstancePtr->Config.CtrlBaseAddress == 0) {
|
||
|
return (XST_SUCCESS);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Only 32-bit data width is supported as of yet. 64-bit and 128-bit
|
||
|
* widths will be supported in future.
|
||
|
*/
|
||
|
if (InstancePtr->Config.DataWidth != 32)
|
||
|
return (XST_SUCCESS);
|
||
|
|
||
|
/*
|
||
|
* Read from the implemented readable registers in the hardware device.
|
||
|
*/
|
||
|
if (InstancePtr->Config.CorrectableFailingRegisters) {
|
||
|
(void) RD(CE_FFA_0_OFFSET);
|
||
|
}
|
||
|
if (InstancePtr->Config.CorrectableFailingDataRegs) {
|
||
|
(void) RD(CE_FFD_0_OFFSET);
|
||
|
(void) RD(CE_FFE_0_OFFSET);
|
||
|
}
|
||
|
if (InstancePtr->Config.UncorrectableFailingRegisters) {
|
||
|
(void) RD(UE_FFA_0_OFFSET);
|
||
|
}
|
||
|
if (InstancePtr->Config.UncorrectableFailingDataRegs) {
|
||
|
(void) RD(UE_FFD_0_OFFSET);
|
||
|
(void) RD(UE_FFE_0_OFFSET);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Write and read the implemented read/write registers in the hardware
|
||
|
* device.
|
||
|
*/
|
||
|
if (InstancePtr->Config.EccStatusInterruptPresent) {
|
||
|
WR(ECC_EN_IRQ_OFFSET, 0);
|
||
|
if (RD(ECC_EN_IRQ_OFFSET) != 0) {
|
||
|
return (XST_FAILURE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (InstancePtr->Config.CorrectableCounterBits > 0) {
|
||
|
u32 Value;
|
||
|
|
||
|
/* Calculate counter max value */
|
||
|
if (InstancePtr->Config.CorrectableCounterBits == 32) {
|
||
|
Value = 0xFFFFFFFF;
|
||
|
} else {
|
||
|
Value = (1 <<
|
||
|
InstancePtr->Config.CorrectableCounterBits) - 1;
|
||
|
}
|
||
|
|
||
|
WR(CE_CNT_OFFSET, Value);
|
||
|
if (RD(CE_CNT_OFFSET) != Value) {
|
||
|
return (XST_FAILURE);
|
||
|
}
|
||
|
|
||
|
WR(CE_CNT_OFFSET, 0);
|
||
|
if (RD(CE_CNT_OFFSET) != 0) {
|
||
|
return (XST_FAILURE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* If fault injection is implemented, inject all possible single-bit
|
||
|
* and double-bit errors, and check all observable effects.
|
||
|
*/
|
||
|
if (InstancePtr->Config.FaultInjectionPresent &&
|
||
|
InstancePtr->Config.WriteAccess != 0) {
|
||
|
|
||
|
const u32 Addr[2] = {InstancePtr->Config.MemBaseAddress &
|
||
|
0xfffffffc,
|
||
|
InstancePtr->Config.MemHighAddress &
|
||
|
0xfffffffc};
|
||
|
u32 SavedWords[2];
|
||
|
u32 ActualData;
|
||
|
u32 ActualEcc;
|
||
|
u32 CounterValue = 0;
|
||
|
u32 CounterMax;
|
||
|
int WordIndex = 0;
|
||
|
int Result = XST_SUCCESS;
|
||
|
int Index1;
|
||
|
int Index2;
|
||
|
int Width;
|
||
|
|
||
|
PrngResult = 42; /* Random seed */
|
||
|
|
||
|
/* Save two words in BRAM used for test */
|
||
|
SavedWords[0] = XBram_In32(Addr[0]);
|
||
|
SavedWords[1] = XBram_In32(Addr[1]);
|
||
|
|
||
|
for (Width = 1; Width <= 4; Width <<= 1) {
|
||
|
/* Calculate counter max value */
|
||
|
if (InstancePtr->Config.CorrectableCounterBits == 32) {
|
||
|
CounterMax = 0xFFFFFFFF;
|
||
|
} else {
|
||
|
CounterMax =(1 <<
|
||
|
InstancePtr->Config.CorrectableCounterBits) - 1;
|
||
|
}
|
||
|
|
||
|
/* Inject and check all single bit errors */
|
||
|
for (Index1 = 0; Index1 < TOTAL_BITS; Index1++) {
|
||
|
/* Save counter value */
|
||
|
if (InstancePtr->Config.CorrectableCounterBits > 0) {
|
||
|
CounterValue = RD(CE_CNT_OFFSET);
|
||
|
}
|
||
|
|
||
|
/* Inject single bit error */
|
||
|
InjectErrors(InstancePtr, Addr[WordIndex], Index1,
|
||
|
Index1, Width, &ActualData, &ActualEcc);
|
||
|
|
||
|
/* Check that CE is set */
|
||
|
if (InstancePtr->Config.EccStatusInterruptPresent) {
|
||
|
CHECK(ECC_STATUS_OFFSET,
|
||
|
XBRAM_IR_CE_MASK, Result);
|
||
|
}
|
||
|
|
||
|
/* Check that address, data, ECC are correct */
|
||
|
if (InstancePtr->Config.CorrectableFailingRegisters) {
|
||
|
CHECK(CE_FFA_0_OFFSET, Addr[WordIndex], Result);
|
||
|
}
|
||
|
/* Checks are only for LMB BRAM */
|
||
|
if (InstancePtr->Config.CorrectableFailingDataRegs) {
|
||
|
CHECK(CE_FFD_0_OFFSET, ActualData, Result);
|
||
|
CHECK(CE_FFE_0_OFFSET, ActualEcc, Result);
|
||
|
}
|
||
|
|
||
|
/* Check that counter has incremented */
|
||
|
if (InstancePtr->Config.CorrectableCounterBits > 0 &&
|
||
|
CounterValue < CounterMax) {
|
||
|
CHECK(CE_CNT_OFFSET,
|
||
|
CounterValue + 1, Result);
|
||
|
}
|
||
|
|
||
|
/* Restore correct data in the used word */
|
||
|
XBram_Out32(Addr[WordIndex], SavedWords[WordIndex]);
|
||
|
|
||
|
/* Allow interrupts to occur */
|
||
|
/* Clear status register */
|
||
|
if (InstancePtr->Config.EccStatusInterruptPresent) {
|
||
|
WR(ECC_EN_IRQ_OFFSET, IntMask);
|
||
|
WR(ECC_STATUS_OFFSET, XBRAM_IR_ALL_MASK);
|
||
|
WR(ECC_EN_IRQ_OFFSET, 0);
|
||
|
}
|
||
|
|
||
|
/* Switch to the other word */
|
||
|
WordIndex = WordIndex ^ 1;
|
||
|
|
||
|
if (Result != XST_SUCCESS) break;
|
||
|
|
||
|
}
|
||
|
|
||
|
if (Result != XST_SUCCESS) {
|
||
|
return XST_FAILURE;
|
||
|
}
|
||
|
|
||
|
for (Index1 = 0; Index1 < TOTAL_BITS; Index1++) {
|
||
|
for (Index2 = 0; Index2 < TOTAL_BITS; Index2++) {
|
||
|
if (Index1 != Index2) {
|
||
|
/* Inject double bit error */
|
||
|
InjectErrors(InstancePtr,
|
||
|
Addr[WordIndex],
|
||
|
Index1, Index2, Width,
|
||
|
&ActualData,
|
||
|
&ActualEcc);
|
||
|
|
||
|
/* Check that UE is set */
|
||
|
if (InstancePtr->Config.
|
||
|
EccStatusInterruptPresent) {
|
||
|
CHECK(ECC_STATUS_OFFSET,
|
||
|
XBRAM_IR_UE_MASK,
|
||
|
Result);
|
||
|
}
|
||
|
|
||
|
/* Check that address, data, ECC are correct */
|
||
|
if (InstancePtr->Config.
|
||
|
UncorrectableFailingRegisters) {
|
||
|
CHECK(UE_FFA_0_OFFSET, Addr[WordIndex],
|
||
|
Result);
|
||
|
CHECK(UE_FFD_0_OFFSET,
|
||
|
ActualData, Result);
|
||
|
CHECK(UE_FFE_0_OFFSET, ActualEcc,
|
||
|
Result);
|
||
|
}
|
||
|
|
||
|
/* Restore correct data in the used word */
|
||
|
XBram_Out32(Addr[WordIndex],
|
||
|
SavedWords[WordIndex]);
|
||
|
|
||
|
/* Allow interrupts to occur */
|
||
|
/* Clear status register */
|
||
|
if (InstancePtr->Config.
|
||
|
EccStatusInterruptPresent) {
|
||
|
WR(ECC_EN_IRQ_OFFSET, IntMask);
|
||
|
WR(ECC_STATUS_OFFSET,
|
||
|
XBRAM_IR_ALL_MASK);
|
||
|
WR(ECC_EN_IRQ_OFFSET, 0);
|
||
|
}
|
||
|
|
||
|
/* Switch to the other word */
|
||
|
WordIndex = WordIndex ^ 1;
|
||
|
}
|
||
|
if (Result != XST_SUCCESS) break;
|
||
|
}
|
||
|
if (Result != XST_SUCCESS) break;
|
||
|
}
|
||
|
|
||
|
/* Check saturation of correctable error counter */
|
||
|
if (InstancePtr->Config.CorrectableCounterBits > 0 &&
|
||
|
Result == XST_SUCCESS) {
|
||
|
|
||
|
WR(CE_CNT_OFFSET, CounterMax);
|
||
|
|
||
|
InjectErrors(InstancePtr, Addr[WordIndex], 0, 0,
|
||
|
4, &ActualData, &ActualEcc);
|
||
|
|
||
|
CHECK(CE_CNT_OFFSET, CounterMax, Result);
|
||
|
}
|
||
|
|
||
|
/* Restore the two words used for test */
|
||
|
XBram_Out32(Addr[0], SavedWords[0]);
|
||
|
XBram_Out32(Addr[1], SavedWords[1]);
|
||
|
|
||
|
/* Clear the Status Register. */
|
||
|
if (InstancePtr->Config.EccStatusInterruptPresent) {
|
||
|
WR(ECC_STATUS_OFFSET, XBRAM_IR_ALL_MASK);
|
||
|
}
|
||
|
|
||
|
/* Set Correctable Counter to zero */
|
||
|
if (InstancePtr->Config.CorrectableCounterBits > 0) {
|
||
|
WR(CE_CNT_OFFSET, 0);
|
||
|
}
|
||
|
|
||
|
if (Result != XST_SUCCESS) break;
|
||
|
|
||
|
} /* Width loop */
|
||
|
|
||
|
return (Result);
|
||
|
}
|
||
|
|
||
|
return (XST_SUCCESS);
|
||
|
}
|
||
|
|