This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[FAQ] : How to test ECC for R5F Cache Memories on AM6x/AM243 devices.

Part Number: SK-AM62B-P1

Tool/software:

Is ECC (SEC/DED) testing possible on R5F internal cache memories? If yes, please provide the steps to do so.

  • The following table lists the type of R5F Cache memory and the type of error injection supported:

    "Errors on instruction cache read
    All parity or ECC errors detected on instruction cache reads are correctable."

    Hence there is no support for DED on I Cache. Note injection is supported by the ECC aggregator, but checking and reporting is not. This is the ARM IP limitation as there is no way to recover from DED error in the I Cache.

  • Following are the steps to test SEC/DED on R5F cache memories on AM6x/AM243 devices:

    1. Enable ECC for R5 Cache memories by setting the ACTLR Register in the startup sequence.

    (Note it is important to enable the ECC before enabling the Cache and entering the application as enabling ECC after Cache is already being used would cause unexpected aborts)

    The value assigned to this register is entirely dependent on your specific use caseWe do not recommend any rigid value for this register. However, considering that single bit errors are automatically corrected, it is logical to avoid aborts for correctable errors. Therefore, you may consider setting the ACTLR register to 101, which will result in an abort only for non-correctable errors.

                                              (Screenshot taken from R5F TRM)

    MRC p15, 0, r0, c1, c0, 0 // Read System Control Register
    BIC r0, r0, #0x1 << 2 // Disable data cache bit
    BIC r0, r0, #0x1 << 12 // Disable instruction cache bit
    DSB
    MCR p15, 0, r0, c1, c0, 0 // Write System Control Register
    ISB // Ensures following instructions are not executed from cache
    MRC p15, 0, r1, c1, c0, 1 // Read Auxiliary Control Register
    ORR r1, r1, #(0x5 << 3)  //Enable ECC for Cache
    MCR p15, 0, r1, c1, c0, 1 // Write Auxiliary Control Register        
    MCR p15, 0, r0, c15, c5, 0 // Invalidate entire data cache
    MCR p15, 0, r0, c7, c5, 0 // Invalidate entire instruction cache
    MRC p15, 0, r0, c1, c0, 0 // Read System Control Register
    ORR r0, r0, #0x1 << 2 // Enable data cache bit
    ORR r0, r0, #0x1 << 12 // Enable instruction cache bit
    DSB
    MCR p15, 0, r0, c1, c0, 0 // Write System Control Register
    ISB 

    2. Enable the export functionality of R5F PMCR register for routing Cache events to ESM/ Pulsar registers.

    asm("MOV R5, #0x0");                                          
    asm("MRC     P15,#0, R5, C9, C12,#0");                  
    asm("ORR     R5, R5, #0x2");                    // Reset event counter        
    asm("MCR     P15,#0, R5, C9, C12,#0");                  
    asm("MRC     P15,#0, R5, C9, C12,#0");                  
    asm("ORR     R5, R5, #0x11");                 
    asm("MCR     P15,#0, R5, C9, C12,#0");                  
    asm("MOV r4, #0x60");        
    asm("MCR p15,#0,r4,c9,c13,#1");

    3. Initialize ESM module using SDL_ESM_init() API and enable the ECC events corresponding to R5F memories: (Attached screenshot is for AM62x. There will be similar events mapped for other devices as well)

  • 4. Perform an invalidate and write back of the entire DCache/ICache before testing every RAM ID

    DCache :

    CacheP_wbInvAll(CacheP_TYPE_L1D)

    ICache :

    CacheP_wbInvAll(CacheP_TYPE_L1P)

    5. Fill the Cache with dummy values by performing a 32KB read from a cached memory.

    DCache :

    #define ARRAY_SIZE 32*1024 // Size of the array in bytes (32KB)    
    uint8_t a[ARRAY_SIZE];    
    uint8_t b[ARRAY_SIZE];    
    for(uint32_t iii=0;iii<ARRAY_SIZE;iii++)    
    {      
    a[iii]=(iii%256)+1;    
    }

    ICache 

    You can perform a read of 8192 dummy instructions to completely fill the ICache.

    void Fill_ICache()
    {
        asm("MOV R0, #0x0");
        asm("MOV R0, #0x0");
        .
        .
        .(8192 times)
        .
        asm("MOV R0, #0x0");
    }

    6. Inject Error using the ECC Aggr. (ECC aggr settings mentioned in the table below)

    Attaching sample code for DData RAM for AM62x below: (The code will be same for all the devices. Only the Ecc Aggr, Base address has to modified depending on the device and R5 core being used)

    a. For Single bit error injection :

    uint32_t *ptr2=(uint32_t *)0x3f00d008; //Set RAM ID     
    *ptr2=0xD; // RAM ID 13 - DData0 RAM ID
    uint32_t *ptr3=(uint32_t *)0x3f00d014; // ECC Ctrl Reg    
    *ptr3=0x28;
    uint32_t *ptr5=(uint32_t *)0x3f00d008; // ECC vector Reg
    *ptr5=0x148000;
    while(((*ptr5>>24)&0x1)!=1) // Polling the Read done bit to ensure ECC aggr. gets properly updated
    
    {
    
        ;
    
    }
    asm("NOP"); 

    b. For Double bit error injection :

    uint32_t *ptr2=(uint32_t *)0x3f00d008; //Set RAM ID     
    *ptr2=0xD; // RAM ID 13 - DData0 RAM ID
    uint32_t *ptr4=(uint32_t *)0x3f00d01C; //ECC Error Control2 reg    
    *ptr4=0x30002; 
    uint32_t *ptr3=(uint32_t *)0x3f00d014; // ECC Ctrl Reg    
    *ptr3=0x28;
    uint32_t *ptr5=(uint32_t *)0x3f00d008; // ECC vector Reg
    *ptr5=0x148000;
    while(((*ptr5>>24)&0x1)!=1) // Polling the Read done bit to ensure ECC aggr. gets properly updated
    
    {
    
        ;
    
    }
    asm("NOP"); 

    Using the above sample code as reference, you can the following settings for different RAM IDs: 

    DCache RAMs
    SEC
    DED
    DTAG

    ECC Error Ctlr1 Reg(0x18)

    0xFD

    ECC Ctlr Reg(0x14)

    0x48

    (force_sec + error_once)

    ECC Error Ctlr2 Reg(0x1C)

    0x30002

    ECC Ctlr Reg(0x14)

    0x30

    (force_ded + force_n_row)

    DDIrty

    ECC Ctlr Reg(0x14)

    0x28

    (force_sec + force_n_row)

    ECC Error Ctlr2 Reg(0x1C)

    0x30002

    ECC Ctlr Reg(0x14)

    0x30

    (force_ded + force_n_row)

    DDATA

    ECC Ctlr Reg(0x14)

    0x28

    (force_sec + force_n_row)

    ECC Error Ctlr2 Reg(0x1C)

    0x30002

    ECC Ctlr Reg(0x14)

    0x30

    (force_ded + force_n_row)

    ITAG

    ECC Error Ctlr1 Reg(0x18)

    0xFD

    ECC Ctlr Reg(0x14)

    0x48

    (force_sec + error_once)

    NA

    IDATA

    ECC Ctlr Reg(0x14)

    0x28

    (force_sec + force_n_row)

    NA

  • 7. Loop through the entire DCache to trigger error for DData and Dtag RAM IDs. For DDirty RAM, evict the entire DCache by reading a different 32KB from cache memory. Similarly, Loop through the entire ICache to trigger error for IData and Itag RAM IDs

    DCache :

    for(uint32_t i=0;i<ARRAY_SIZE;i++)    
    {    
    b[i]=a[i];    // Same arrays as defined in Step 5
    } 

    ICache :

    Fill_ICache() //Same function as defined in Step 5

    Note :

    1.Error injection has to be additionally disabled inside the ISR(For single bit errors) or abort handlers(for double bit errors) by setting the ECC Ctlr Register(0x14) to 0, to prevent further error injections.

    // Add the below code inside the ISR/Abort Handler whenever an ECC error is detected
    
    // if error == R5F Cache ECC Error {
        uint32_t *ptr3=(uint32_t *)0x3f00d014; // ECC Ctrl Reg    
        *ptr3=0x0;
        uint32_t *ptr5=(uint32_t *)0x3f00d008; // ECC vector Reg
        *ptr5=0x148000;
        while(((*ptr5>>24)&0x1)!=1) // Polling the Read done bit to ensure ECC aggr. gets properly updated
        
        {
        
            ;
        
        }
    //}
    

    2. While performing double bit error injection, we get a synchronous abort for DData and Dtag RAM IDs and an asynchronous abort for DDirty RAM. In case there is a delay in the triggering of the Async abort check and clear the A bit of the CPSR register, that should trigger the abort immediately after the error gets detected.