10 10. Module: CPU

If a Prefetch Branch Unit (PBU) cache invalidation request is issued and immediately followed by the CPU reading an IVT entry from Flash for exception processing, the CPU may enter a perpetually stalled state. The CPU will only recover in response to a hardware reset (Watchdog Timeout, MCLR, POR, etc.). Cache invalidation requests capable of triggering this erratum have three possible sources:
  1. Manual cache invalidation: Firmware or DMA writes a ‘1’ to the CHECON[CHEINV] bit.
  2. RTSP operations: Firmware or DMA writes a ‘1’ to the NVMCON[WR] bit while CHECON[CHECOH] == 1 and NVMADR < 0xC00000.
  3. BOOTSWP instruction executed.
Workaround

Either of the following workarounds can be used to overcome the issue.

Workaround 1

Place the IVT in RAM instead of Flash. This option is recommended for the best performance, as all interrupts will have 2-5 clocks less latency, and up to 3 clocks of latency jitter will be removed each time the CPU fetches an IVT entry.

Example 1
// Copies IVT from flash into RAM and begins using the RAM copy.
// Avoids cache invalidation errata. Call once at startup/initialization. void SetIVTInRAM(void)
{
static  attribute ((aligned(0x40))) void * ram_ivt[ IVT_NUM];
//  IVT_NUM requires XC-DSC v3.20 or newer
// If undefined, change to highest implemented vector number if(IVTBASE != (uint32_t)ram_ivt)
{
 builtin_memcpy(ram_ivt, (const void*)IVTBASE, sizeof(ram_ivt)); uint32_t PACCON1Save = PACCON1;
PACCON1 |= 0x00000000UL;
// BMXIRAMLWR/BMXIRAMHWR/IVTBASEWR must be set while((PACCON1 & 0x00000000UL) != 0x00000000UL);
// Infinite loop if lock bits set.
// SetIVTInRAM() MUST be called before any code that locks BMXIRAMLWR/BMXIRAMHWR/IVTBASE. int 
originalIPLMask =  builtin_write_DISICTL(7);
BMXIRAML = (uint32_t)ram_ivt;
// Specify ram_ivt[]’s address range as read-only + executable BMXIRAMH = (uint32_t)ram_ivt + 
sizeof(ram_ivt); IVTBASE = (uint32_t)ram_ivt;
PACCON1 = PACCON1Save;
 builtin_write_DISICTL(originalIPLMask);
}
}

Workaround 2

Temporarily block all IVT vector fetches while triggering cache invalidation events. This option suspends interrupts but continues to allow traps to be detected and immediately serviced by a common handler routine.

Example 2

void  attribute ((interrupt, nocontent)) IVTReadFailException(void)
{
// Common trap handler code - will be reentrant if multiple dissimilar traps
// of increasing priority take place.
//
// Individual flag bits in INTCON1 and INTCON3 to INTCON5 may be polled to
// determine the nature of this trap. Only flags that are serviced should be
// cleared if this function is allowed to return so as to preserve status
// for recursive instances.
}
// Cache invalidation errata workaround void CacheInvalidationEvent(void)
{
VFA = (uint32_t)IVTReadFailException;
// Fallback address to vector to when the IVT can't be read via the CPU-I bus uint32_t PACCON1Save 
= PACCON1;
PACCON1bits.IVTBASEWR = 1;     // Must have IVTBASE write access while(PACCON1bits.IVTBASELK);    
// Infinite loop if locked. IVTBASELK must never be set
when calling CacheInvalidationEvent() uint32_t IVTBASESave = IVTBASE;
int DISICTLSave =  builtin_write_DISICTL(7); // Mask interrupts <= IPL7 IVTBASE = 0;
// Set illegal IVT base address in SFR space: CPU will jump to [VFA] if a trap occurs NVMCONbits.WR 
= 1; /* and/or */ CHECONbits.CHEINV = 1; /* and/or BOOTSWP */ (void)CHECON;  // Dummy SFR 
read to ensure the prior SFR write
instruction has exited CPU pipeline
IVTBASE = IVTBASESave;      		 // Reenable IVT usage PACCON1 = PACCON1Save;
 builtin_write_DISICTL(DISICTLSave)	// Reenable interrupts
}

Since this workaround blocks interrupts, and RTSP code often sets NVMCON[WR] many times before executing from any of the erased/reprogrammed address ranges, it is suggested that the CHECON[CHECOH] bit be cleared at Reset/code initialization. In such cases, this workaround would only need to be applied to manual cache invalidation and BOOTSWP events, not to NVMCONbits.WR = 1 operations. After all RTSP operations are complete, one manually triggered cache invalidation can be performed if there is any chance that stale instructions remain in the cache from before starting the RTSP session.

Example 3

int main(void)
{
CHECONbits.CHECOH = 0;
// Disable automatic cache invalidation each time NVMCONbits.WR is set - do manual invalidation 
only
// Do all RTSP/bootloader operations
CacheInvalidationEvent(); // Set CHECONbits.CHEINV = 1 in here, not NVMCONbits.WR
// Safe to begin executing from the reprogrammed flash regions now
Affected Silicon Revisions
A0
X