【发布时间】:2019-12-05 15:59:08
【问题描述】:
我在玩 STM32H753 的 L1-cache。
我想要做的是故意挑起缓存和 RAM 之间的不一致,如下所示:
- 将 SRAM 区域设置为可直写缓存
- 启用数据缓存
- 向 RAM 中的变量写入内容 -> 数据将同时写入缓存和 RAM
- 禁用缓存不使其失效
- 向同一个变量写入其他内容 -> 只会修改 RAM,不会修改缓存
- 重新启用缓存,再次启用,但不会使其失效
- 读取 RAM -> 我希望读取旧值而不是新值,因为此时缓存中应该有命中,因为缓存行应该仍然有效并且它应该仍然包含旧值?
代码如下:
volatile uint32_t someDummyVariable ;
int main(void)
{
MPU_Region_InitTypeDef MPU_InitStruct;
HAL_Init();
/* Configure the MPU attributes as Write-through for SRAM */
HAL_MPU_Disable();
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.BaseAddress = 0x20000000;
MPU_InitStruct.Size = MPU_REGION_SIZE_32MB;
MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE; // -> means write through ?
MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
MPU_InitStruct.Number = MPU_REGION_NUMBER0;
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
MPU_InitStruct.SubRegionDisable = 0x00;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
HAL_MPU_ConfigRegion(&MPU_InitStruct);
/* Configure the MPU attributes as WT for the Flash */
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.BaseAddress = 0x08000000;
MPU_InitStruct.Size = MPU_REGION_SIZE_16MB;
MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
MPU_InitStruct.Number = MPU_REGION_NUMBER1;
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
MPU_InitStruct.SubRegionDisable = 0x00;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
HAL_MPU_ConfigRegion(&MPU_InitStruct);
HAL_MPU_Enable(MPU_HARDFAULT_NMI);
SCB_EnableDCache();
// write something in a variable in RAM -> thanks to write-through attribute
// it will be copied to real RAM, not only to the cache
someDummyVariable = 0x12345678;
// disable cache without invalidating it
SCB->CSSELR = 0U; /* select Level 1 data cache */
__DSB();
SCB->CCR &= ~(uint32_t)SCB_CCR_DC_Msk; /* disable D-Cache */
__DSB();
__ISB();
// write something else to RAM -> will NOT be written to cache
someDummyVariable = 0xAAAAAAAA;
// enable cache again (without invalidating or cleaning it)
__DSB();
SCB->CCR |= (uint32_t)SCB_CCR_DC_Msk; /* enable D-Cache */
__DSB();
__ISB();
// now we should read the old value that is still in the cache
if ( someDummyVariable != 0x12345678 )
{
__NOP();
}
使用 Keil 5 编译,-O0。变量 write 是通过 STR 完成的(我的意思是:据我所知,没有奇怪的 CPU 优化)。
我检查了 MPU 寄存器的值,RAM 变量的地址(确实在 MPU 区域内)。
算法和/或代码有问题吗?
编辑:修复 MPU 配置
【问题讨论】:
-
为什么要在运行时禁用缓存?
-
我需要运行缓存的自检。该算法是在上一代产品上实现的(在不同的 MCU 上),如果可能,我们希望保留类似的算法
-
写入内存,并将 MPU 区域设置为回写。将 MPU 区域更改为不可缓存,然后将其读回。我认为这会导致不一致。如果这不起作用,则与我过去所做的类似,但不记得确切的细节。基本上在 MPU 中使用不同的缓存设置访问相同的内存会导致问题。
-
是的,这实际上是我现在想要做的:将 RAM 设置为回写、写入、禁用缓存、读取:预期不一致。