cache ram测试用例说明文档
虽然本例程名称叫做unit_cache_ram_test,但是ram仅包含一个读写测试,因此本文档主要介绍cache。
cache简介
cache主要用于将外部的储存器(flash、psram、dmem等)映射到系统的内存空间,是的CPU通过cache可以透明的访问这些大的存储空间,cache屏蔽了这些外部存储器访问的复杂性。
cache的工作原理
cache本质上是基于cache line数据结构的一种多对一的映射,kl3的cache line是32bytes,cache自身存储空间是32KB,所以系统空间的每个32KB的第一个32bytes共享cache的第一个cache line,所以需要一个tag来存储cache line当前道理是哪一块32B的数据。
一个cache可以是多个way的,意思是每个cache line其实有多个32B的存储器,这样当发生cache miss的时候,替换操作占用多个way的一个,从而降低cache line冲突,提高系统访问效率。
kl3 cache特性
- 一共5个buffer cache,其中3个32KB容量,2个64KB容量。
- 2 way,分别对应flash和psram空间的映射。
- 可灵活配置为cache或者on-chip ram使用。
- 支持“指定地址范围”的flush操作。
- 支持全cache clear操作。
- 支持cache miss统计。
- 支持“指定地址段范围”访问监测(?)。
cache工作模式
cache主要有四种工作模式。
clear mode
当设置Clear mode的时候,cache内部的状态机会把cache整个tag memory中的信息全部清空,完成后cache中是完全空白的。
在clear过程中,如果系统有下发读写操作,cache会等clear操作完成后才会响应这些操作。
如果在clear mode有效的时候,cache还在进行读写操作,则会等待当前读写操作完成之后才会响应clear操作。
【注】clear操作只会对tag信息进行操作,在这个过程中如果有dirty的cache line,不会对这些cache line发起flush操作,cache line dirty数据会丢失。
flush mode
当设置flush mode的时候,软件会预先设置一段将要flush的地址空间(起始地址、结束地址),cache内部的状态机会控制扫描所有的tag memory,检查要flush的地址空间内的cache line时候存在于cache中。如果扫描到有个cache line是需要flush的,则检查其是否是dirty的,如果dirty则会吧这个cache line的数据flush到external memory中对应的位置,然后把这个cache line对应的tag设置为无效的cache line,如果这个cache line不是dirty的,则直接设置这个cache line对应的tag为无效的cache line。
flush mode主要是把cache中的dirty数据flush到exeternal memory中,姐姐cache和external memory之间的数据一致性问题。
normal mode
在非clear和flush mode下即为normal mode,此时cache响应系统正常的读写请求。
如果cache hit,则直接响应系统的读写请求。
如果cache miss,则自动进行cache line data的替换操作。
monitor mode
cache空间中可能存在多个堆栈,当发生堆栈数据被破坏的时候,可以开启cache的monitor模式。
通过cache_acc_saddr和cache_acc_eaddr定义了检测时允许访问的空间。
通过cache_mon_saddr和cache_mon_eaddr定义了检测时允许访问空间内部禁止访问的空间(即禁止访问的空间应当在允许访问空间范围内)。
当访问到禁止访问空间以及访问到允许访问空间以外的空间时,都会触发访问错误告警。
测试例程说明
cache_ram测试例程使用到的外设包含cache、ram、smc、sfc、uart、gptimer。
- ram:测试对象,主要测试读写正确性。
- cache:测试对象,主要测试cache访问外部memory,以及cache自身功能完整性。
- sfc:辅助测试对象,用于辅助测试cache访问外部flash。
- smc:辅助测试对象,用于辅助测试cache访问外部psram。
- uart:使用uart0,实现调试信息打印,接收case配置信息等与PC的交互功能。
- gptimer:使用gptimer0,用于测试“普冉flash工厂模式”时延时功能。
cache_ram测试例程遵循自动化测试框架,在例程执行之后,初始化串口0,通过串口发送“start”字段到PC,并等待PC发送“config”字段来获取本次需要执行的测试case。
在获取到case组合之后,初始化cache、ram、sfc、smc、psram、flash以及gptimer,并根据case组合开始执行测试case。
case0:ram读写测试
本case用于测试ram读写功能。读写的区域为除代码段、数据段、heap空间以外的区域。
通过导入链接脚本中定义的符号(_start、_flash_end、_data、_iram_end),确定ram需要测试的区域。一共有3个区域可进行读写测试:
- ram开始位置保留给rom代码使用的空间。
- dtest链接脚本中flash段剩余空间。
- dtest链接脚本中iram段剩余空间。
dtest程序汇总,dram段存放数据段后剩余的空间全部用作heap,因此不参与测试。
测试的方法相对简单,在所有参与测试的区域写入0x55或者0xaa,并读取出数据对比是否与写入数据一致。
测试结果通过。
case1:cache读写外部存储器
本case用于测试cache对外部存储器的读写,其测试流程如下:
- 使用cache0在psram的指定位置写入数据A。
- 使用sfc api在flash指定位置写入数据A(cache无法直接对flash erase或者program)。
- 使用所有cache读取psram指定位置,得到数据B,如果数据A和数据B不相等,则判定测试失败。
- 使用所有cache读取flash指定位置,得到数据C,如果数据C和数据A不相等,则判定测试失败。
【注】:在写入psram数据是使用到cache_flush函数,在读取数据时使用到cache_invalid函数,这两个函数在设计上传入的地址参数应该减去cache基地址,但是当cache同时连接到flash和psram时,没有基地址的地址参数将不能区分其属于flash或者是属于psram(除非操作flash地址时加上0x4000000),在实际使用中,地址参数加上cache基地址依然可以正常工作(asic已经确认可以正常工作),因此后续大core使用这两个api时,地址参数需要加上cache基地址)。
case2:cache当做内部ram使用。
本case用于测试cache作为内部ram使用。
kl3 cache可以配置为内部ram使用,需要使能cache,并将cache_ctr0寄存器中的icache_mode位置1即可。作为ram使用时,其ram空间为cache开始位置的前32KB(icache)\64KB(dcache)。
测试方法相对简单,配置完成之后对地址空间进行读写操作即可,测试结果通过。
cache3:cache脏数据和miss
本case用于测试cache脏数据、数据同步、cache miss以及auto load功能。
在使用cache时,以下两种情况会导致cache中数据与实际存储设备中的数据不一致的情况:
- cache在读取存储设备数据之后(数据已经保存在cache中),通过其他手段(如其他cache、sfc api,smc api等)更改数据源保留的数据,此时cache并不知道数据已经被更改。
- cache读取存储设备数据之后,更改了cache数据,此时数据更改的行为仅发生在cache内部,未同步到存储设备中。
以上两种情况,则可称cache中的数据为脏数据(dirty data),此时需要等待cache miss,才会触发cache同步数据,根据情况从存储设备中重新读取数据或者将数据写入到存储设备中。
当然,我们也可以选择软件干预的方式,在任何时候实现数据同步,数据同步设计到的cache api如下:
- cache_clear:对应cache clear mode,清空所有的cache tag,下次使用cache读时,必定重新从存储设备中读取新数据。除非很有把握使用clear,否则建议使用invalid清理数据。
- cache_invalidata:相当于指定地址范围的cache clear,cache会遍历所有的tag,如果存在tag对应的地址在invalid地址范围内,则抛弃该tag对应数据,此时重新访问该地址范围时,将会重新读取存储设备的数据。
- cache_flush:对应flush mode,将cache中的数据同步到存储设备中,flush操作在之前的测试中已经使用,则不再测试。
选取sfc作为测试对象,设定测试地址为addr,测试数据data,测试方法如下:
- 使用erase指令擦除addr对应的sector。
- 使用cache读取addr得到数据A。
- 使用sfc api写入数据到addr。
- 使用cache读取addr得到数据B。
- 使用cache clear api清理cache数据,并重新读取addr得到数据C。
- 此时A应该等于0xffffffff,B等于A,C等于写入数据data,否则判定执行失败
- 将cache clear替换为cache invalid api,重新执行步骤1到步骤6。
- 将cache clear替换为连续读取32KB非addr的地址空间数据(使所有的cache line都被暂用,cache空间被填满),之后重新读取addr数据,此时A应该等于0xffffffff,C等于写入数据data,否则判定失败。
以上测试结果通过。
case4:cache line测试
cache line的测试来源于beetle的代码,测试代码的原作者是“董伟“,这里仅简单介绍测试的原理:
我们可以把cache或者存储设备的存储空间想象成由横坐标和纵坐标组成的网格坐标系,正常情况下,各网格相邻的轴互不影响。一旦地址总线或者数据总线发生异常(粘连、短路、断路等),则对总线发起的操作将影响到相邻的总线,或者操作将会不成功。
- 数据总线:对数据总线的测试相对简单,即在指定地址写入数据并读出,判断数据是否一致即可,数据总线为8位,每次写入的数据仅置位1个bit(如0x1,0x2,0x4等),保证所有地址总线均能改变电平,如果数据总线发生粘连,则在改变其中一条线电平时,与之粘连的线电平也会变化,则读出的数据会与写入的数据有差异。
- 地址总线:选定一个地址A,并以2的幂次方为增量,在这些地址上都写入0x55,然后在地址A写入0xaa,重新读取之前写入的地址,对比数据是否发生变化,交换0x55和0xaa,重复上述流程。
case5:cache地址监控
本功能在KL3中已经不再支持,硬件已经停止维护该功能,实际测试时也失败。此处仅介绍其原理。
地址监控是为了应对如栈空间冲突、地址异常访问等情况而准备的调试手段,地址监控功能允许配置cache允许访问的空间(acc_addr)和被监控空间(mon_addr),要求监控空间处于允许空间的内部,在配置完成,使能地址监控功能后,如果cache访问了mon_addr地址空间以及出acc_addr地址空间以外的地址范围时,将触发告警,通过读取mon_int_sts寄存器可获得告警状态,使用该状态能够判定地址是否越界等异常。
case6:sfc、smc io share
kl3确认不采用io share方案,且目前的image均不支持io share,因此不再验证该功能(代码保留,但是测试代码未得到验证),这里仅简述其功能原理。
在启用io share之后,sfc将共用smc的clk和sio[0:3]信号,cs信号使用原有的cs信号。io share的优势是可以节约IO。
case7:sfc、smc io remap
该case需要用于测试sfc或者smc自身的io remap功能。
sfc、smc在设计时对内部信号做了编号,根据编号和gpio之间进行mapping,可以实现信号支持在指定GPIO范围内随意映射,以方便芯片封装bonding。
- sfc外设内部的信号包含clk、si、so、wp、hold、cs0、smc_cs(不使用)、cs1。
- smc外设内部的信号包含clk、sio0、sio1、sio2、sio3、cs。
在测试时,修改外设对应的寄存器即可实现remap(sfc对应的寄存器为SPI_IO_MAP0,smc对应的寄存器为SMC_SPI_IO_MAP0),如sfc该寄存器初始化为0x88543210,是标准的映射关系,如果想交换wp和hold,只需要配置为0x88534210即可。
需要注意的是,sfc/smc 控制器产生的是clock enable,如果clock换了的话,ahb_reg中的EMC_PHY_CFG寄存器需要同步修改,才能把clk绑定到其他gpio。
手动测试io remap功能的方法是循环读取flash、psram的数据,并在每次读取的间隔时更改寄存器配置,并在读取执行时使用逻辑分析仪抓取时序图,观察信号是否按配置发生交换。测试结果通过。