Due to failures when running different SYS/BIOS examples on a Cortex-A15 in a 66AK2H14, due to data in the cache from a previously run apparently getting flushed to RAM, was single stepping the code in bios_6_45_01_29\packages\gnu\targets\arm\rtsv7A\boot.asm which should be invalidating the Cortex-A15 caches. That code writes to the CSSELR register to select a cache, and then reads the CCSIDR register to determine the cache size to invalidate.
When stepping initially thought there was a bug in that the SYS/BIOS boot.asm source file wasn't selecting the cache correctly. On further investigation, when single stepping code writes to the CSSELR register don't seem to take effect. The following bare-metal program was created using the GNU v4.9.3 compiler to illustrate the issue:
/* * main.c */ #include <stdint.h> /* * Write the level and type you want to Cache Size Selection Register(CSSELR) * to get size details from Current Cache Size ID Register(CCSIDR) */ static void set_csselr(uint32_t level, uint32_t type) { const uint32_t csselr = level << 1 | type; /* Write to Cache Size Selection Register(CSSELR) */ asm volatile ("mcr p15, 2, %0, c0, c0, 0" : : "r" (csselr)); asm volatile ("isb"); } static uint32_t get_csselr(void) { uint32_t csselr; /* Read current CP15 Cache Size Selection Register(CSSELR) */ asm volatile ("mrc p15, 2, %0, c0, c0, 0" : "=r" (csselr)); return csselr; } static uint32_t get_ccsidr(void) { uint32_t ccsidr; /* Read current CP15 Cache Size ID Register */ asm volatile ("mrc p15, 1, %0, c0, c0, 0" : "=r" (ccsidr)); return ccsidr; } static uint32_t get_clidr(void) { uint32_t clidr; /* Read current CP15 Cache Level ID Register */ asm volatile ("mrc p15,1,%0,c0,c0,1" : "=r" (clidr)); return clidr; } struct { uint32_t clidr; uint32_t initial_csselr; uint32_t l1d_csselr; uint32_t l1d_ccsidr; uint32_t l1i_csselr; uint32_t l1i_ccsidr; uint32_t l2_csselr; uint32_t l2_ccsidr; } cp15_results; int main(void) { cp15_results.clidr = get_clidr (); cp15_results.initial_csselr = get_csselr (); set_csselr (0, 0); /* L1 data cache */ cp15_results.l1d_csselr = get_csselr (); cp15_results.l1d_ccsidr = get_ccsidr (); set_csselr (0, 1); /* L1 instruction cache */ cp15_results.l1i_csselr = get_csselr (); cp15_results.l1i_ccsidr = get_ccsidr (); set_csselr (1, 0); /* L2 unified cache */ cp15_results.l2_csselr = get_csselr (); cp15_results.l2_ccsidr = get_ccsidr (); return 0; }
The program selects different caches by writing to the CSSELR register, and then reading the CCSIDR register for the selected cache. The CSSELR register is also read back The results are stored in a global structure to be checked in the debugger (so that don't need semihost support).
The following screen shot shows the correct results after the program was set to free-run at main, and then suspended once _exit has been entered:
The expressions view shows that:
- l1d_ccsidr has the expected value for the 32 Kbyte L1 data cache (as decoded from the ARMv7-A Architecture Reference Manual)
- l1i_ccsidr has the expected value for the 32 Kbyte L1 instruction cache
- l2_ccsidr has the expected value for the 4 Mbyte L2 cache
- l1d_csselr, l1i_csselr and l2_csselr show the expected read-back values for the CSSELR register.
The following screen shot shows incorrect results after using Step-Over to step through the main function:
The expressions view shows that:
- l1d_csselr and l2_csselr have the incorrect value of 1 (the L1 instruction cache), meaning the writes to the CSSELR register to select the L1 data and L2 caches failed to change the CSSELR register.
- l1d_ccsidr and l2_ccsidr have the size of what is the L1 instruction cache, due to the writes to the CSSELR register not taking effect.
The setup is:
- CCS 6.1.3.00033, with TI Emulators 6.0.228.0
- A 66AK2H14 Rev 2 device in a EVMK2H Rev 4 board
- Using the EVMK2H XDS200 USB onboard debug probe
- The EVMK2H boot mode set to "SLEEP W/ SLOW PLL & SLOW ARM PLL" to prevent uboot from running from flash, and the xtcievmk2x_arm.gel script used on the Cortex-A15 to initialize the device.
- The debug project properties for the Cortex-A15 set to the default of Disable interrupts when source stepping (selecting to not disable interrupts didn't produce the correct behavior when stepping)
The test project is attached 66AK2H14_A15_cache_ops.zip