1 KeyStone DSP 存储器系统简介
KeyStone DSP 存储器架构如图1 所示。
图1 KeyStone DSP 存储器架构
对不同的DSP,存储器的大小可能不同,DSP 核和EDMA 传输控制器的个数也可能不同。表1比较了KeyStone I 系列中常用的3颗DSP。
表1 KeyStone I 存储器系统比较
2 存储器测试算法
本文介绍几种存储器测试算法,并讨论这几种算法的用途。
2.1 数据测试
下面是数据测试的伪代码:
for(memory range under test)
fill the memory with a value;
for(memory range under test)
read back the memory and compare the readback value to the written value
通常,这个测试会被执行几次,每次填充的值不一样。常用的填充值包括0x55555555,0xAAAAAAAA, 0x33333333, 0xCCCCCCCC, 0x0F0F0F0F, 0xF0F0F0F0, 0x00FF00FF,0xFF00FF00FF00, 0xFFFFFFFF, 0。
这个测试可以用来检测数据比特粘连(bit-stuck)问题,例如,如果,
written value = 0, readback value = 0x8,
表示bit 3 粘连到1.
如果
written value = 0xFFFFFFFF, readback value = 0xFFFFFFFE,
表示bit 0 粘连到0.
如果能正确的写入并读出0x55555555(或0xAAAAAAAA),说明相邻的两个比特没有粘连;如果能正确写入并读出0x33333333(或0xCCCCCCCC),说明相邻的4 个比特没有粘连;如果能正确写入并读出0x0F0F0F0F(或0xF0F0F0F0),说明相邻的8 个比特没有粘连…
这个算法既可以用来测试数据总线连接,也可以用于测试存储器单元。当用于测试存储器单元时则每一个存储单元都需要写读所有的值,这将是比较耗时的测试;而用于测试数据总线连接时,只需要把所有的值都写读一遍就可以了(地址不限)。
2.2 地址测试
地址测试的伪代码如下:
for(memory range under test)
fill each memory unit with its address value;
for(memory range under test)
read back the memory and compare the readback value to the written value
这个测试可以用来检测地址比特粘连(bit-stuck)问题。例如,如果
written value = 0 at address 0
written value = 1 at address 1
written value = 2 at address 2
written value = 3 at address 3
……
readback value = 2 at address 0
readback value = 3 at address 1
readback value = 2 at address 2
readback value = 3 at address 3
……
则说明地址线的比特1 粘连,因为地址0,2 中的数据相同,地址1,3 中的数据相同。
这个测试的主要目的是测试地址线和存储器中的地址译码单元,但它实际上对所有存储单元都做了数据写读,所以在一定程度上也测试了数据总线和存储单元。如果由于测试时间的限制,只允许对整个存储器空间进行一遍写读测试时,本节介绍的地址测试是首选。
本文选自电子发烧友网6月《智能工业特刊》Change The World栏目,转载请注明出处!
2.3 走比特测试
走比特测试包括走“1”和走“0”测试。走比特测试即可测试数据,也可以测试地址。
走“1”指测试的数据或地址中只有一个比特为“1”,而所有其它比特为“0”,而且连续的访问中每一次“1”的位置都会移动一个比特,看起来好像是“1”在总线上走。而走“0”测试只是把测试的数据反了一下,看起来就像是一个“0”在总线上走。
2.3.1 数据走比特
数据走比特测试的伪代码如下:
bit_mask_value = 1;
for(number of valid data bits)
{
write bit_mask_value to memory;
readback the data and compared to written value;
inversed_bit_mask_value = bit inverse of bit_mask_value;
write inversed_bit_mask_value to memory;
readback the data and compared to written value;
bit_mask_value = bit_mask_value<<1; //bit walking
}
这个测试可以检测数据比特粘连(bit-stuck)问题,更重要的是,它还可以检测比特间串扰。如果比特之间存在串扰,而这个测试让一个比特与所有其它比特都是相反的,那么其它比特对它的干扰会被最大化,从而让问题暴露出来。
例如,如果
written value = 0x00000010, readback value = 0
written value = 0xFFFFFFEF, readback value = 0xFFFFFFFF
这往往说明比特4 被其它比特干扰。
这个算法既可以用来测试数据总线连接,也可以用于测试存储器单元。当用于测试存储器单元时则每一个存储单元都需要走“1”走“0”,这将是最耗时的测试;而用于测试数据总线连接时,只需要走一遍“1”,再走一遍“0”就可以了(地址不限)。
2.3.2 地址线走比特
地址走比特用于测试地址总线的连接。地址线走比特测试的伪代码如下:
Write 0 to first address;
Write 0xFFFFFFFF to last address;
bit_mask_value = 1;
for(number of valid address bits)
{
write bit_mask_value to address of bit_mask_value;
readback the data at first address and compare to 0;
inversed_bit_mask_value = bit inverse of bit_mask_value;
write inversed_bit_mask_value to address of inversed_bit_mask_value;
readback the data at last address and compare to 0xFFFFFFFF;
bit_mask_value = bit_mask_value<<1; //bit walking
}
和数据走比特类似,这个测试既可以检测地址比特粘连(bit-stuck)问题,还可以检测地址比特间串扰。
例如,如果
written value = 16 at address 16
readback value = 16 at address 0
written value = 0xFFFFFFEF at address 0xFFFFFFEF
readback value = 0xFFFFFFEF at address 0xFFFFFFFF
测试中,想要写往地址16 的数据实际被写到地址0;而想要写往地址0xFFFFFFEF 的数据实际被写到最后一个地址单元。这往往说明地址比特4 被其它比特干扰。
2.4 浮动总线问题
如果测试软件写入并很快从相同地址读出一个值的时候,如果数据线上存在电容特性,写操作会给数据线上的电容充电,总线会短暂的保持它的状态。当测试软件读操作时,总线会返回刚写入的值,即使实际上该数据并没有正确地被写入存储单元。这就是浮动总线(floating buses)问题。
浮动总线可能会“欺骗”简单的测试程序,为了规避浮动总线问题,需要在紧邻的对相同地址的写和读操作之间对其它地址写入一个和原来写的数据相反的数据。例如,
write A to address X;
write inversion of A to address Y;
read value from address X;
这样,浮动总线的问题就可以规避了。
2.5 测试结果的深入分析
从存储器测试结果的初步分析中,如果我们发现比特粘连或干扰,还需要进一步深入分析原因。通常原因可能来自于三方面:
1. 对于外接存储器,PCB 出问题的可能性比较大。最常见的包括焊接问题或设计问题。例如,某个比特被短接到电源或地。通常我们可以用万用表测量信号线之间或信号线和电源或地之间的阻抗来定位这种问题。串扰问题的定位则比较复杂,可能需要用示波器来测试所有相关的信号来确定串扰源。
2. 存储单元失效。如果是外接存储器,我们可以用示波器或逻辑分析仪在总线上监测写入和读出的数据,如果总线上监测到的写数据是对的,而读出的数据是错的,则往往是存储单元失效。
3. 存储控制器失效。如果我们排除了以上问题而怀疑存储控制器时,可以把好的板子和坏的板子上的控制器互换,如果问题跟着控制器走,则往往说明是控制器失效。
本文选自电子发烧友网6月《智能工业特刊》Change The World栏目,转载请注明出处!
3 存储器测试覆盖率
完善的存储器测试应该涵盖:
·系统中所有的存储器
·所有可以访问存储器的模块,包括DSP 核和DMA 传输控制器
·所有不同的访问路径
3.1 用不同的主模块测试
如图1 所示,主要有三个主模块可以访问存储器:
·DSP 核可以访问所有存储器
·EDMA 可以访问所有存储器
·IDMA 只可以访问每个核本地的L1 和L2 存储器
理论上,我们应该用所有的主模块测试所有可访问的存储器,但这样有太多组合,很多重复的测试可能浪费很多时间。所以,测试的组合需要被优化,既保证所有主模块和存储器都被覆盖,又要避免无用的重复测试。
通常DMA 访问存储器的效率比DSP 核高很多,所以,对外部大存储器的测试优先采用EDMA。
用DMA 测试存储器是,我们需要一个额外的缓冲区 (buffer),测试流程如下:
DSP core wirtes test data to the DMA buffer
DMA copy the contents of the DMA buffer to the memory under test
DMA copy the contents of the memory under test back to the DMA buffer
DSP core reads the contents in DMA buffer and compare to expected value.
通常,用于DMA 测试的缓冲区是一个位于L2 中的比较小的缓冲区,而被测试的存储器往往要大得多,所以上述测试流程需要被重复很多遍才能完成对整个存储器的测试。
EDMA 有多个传输控制器,它们可以被交替使用来保证它们都被用到。例如,我们可以用EDMATC1 来填充并回读第一组数据,然后用EDMA TC2 来填充并回读第二组数据…
请注意,在多核DSP 中,EDMA 必须用全局地址来访问L1 和LL2 存储器。
3.2 测试系统中所有的存储器
如图1 所示,Keystone 系统中主要有4 种类型的存储器,它们都应该被测试到。
3.2.1 内部L1 存储器
通常,我们建议用IDMA 测试内部L1 存储器。测试前,L1 存储器应该被配置成普通存储器而不是cache。
DSP 核可以测试本核的L1D 存储器,但DSP 核不能测试本核的L1P 存储器。
在多核DSP 上,如果我们想在一个核上运行程序来测试另一个核的L1 存储器,我们应该用EDMA 而不能用IDMA,因为IDMA 只能访问本核的存储器。在对其它核的存储器测试时,其它核不能运行程序。
3.2.2 内部LL2 存储器
LL2 可以被系统中所有的主模块测试。根据通常的使用情况,我们可以用DSP 核和EDMA 来测试本地LL2 存储器。
通常,存储器测试代码和数据缓冲区都在本地LL2 存储器。所以,测试程序应该检测被测试代码和测试缓冲区占用的空间大小,而仅对剩下的空闲空间进行测试。
尽管被测试代码和测试缓冲区占用的存储区没有被严格的测试算法测试,通常,如果这个区域有问题,测试程序往往会失败。所以,从一定程度上说,这块存储器也是被覆盖了的。如果真的需要用严格的测试算法来测试所有的空间的话,我们需要两个测试程序,一个测试程序占用存储器前半部分,而测试后半部分;另一个测试程序占用存储器后半部分,而测试前半部分。
在多核DSP 上,如果我们想在一个核上运行程序来测试另一个核的LL2 存储器,EDMA 和DSP核都可以用来做测试。在对其它核的存储器测试时,其它核不能运行程序。
3.2.3 内部共享SL2 存储器
每个DSP 核和DMA 都有单独的总线访问共享SL2 存储器,测试应该涵盖每条总线,通过每个DSP 核和DMA 来测试SL2 存储器。
DSP 核通过缺省地址空间(从0x0C000000 开始)访问SL2 会经过cache 和prefetch buffer。要绕过cache 和prefetch buffer 访问SL2,必须把SL2 重新映射到其它地址空间,并把这个地址空间设置(通过MAR 寄存器)成不可cache,不可prefetch。测试应该涵盖这两种情况。
3.2.4 外部DDR 存储器
外部DDR 在测试之前需要被正确配置。如果DDR 测试在某些板子上通过,而在另一些板子上失败,可以尝试放松一些DDR 的时序参数,如果这样能让测试通过则往往说明DDR 接口存在时序问题。
DSP 核和EDMA 都应该被用来测试DDR 存储器。而对DSP 核的测试,既需要测试通过cache访问的情况,也需要测试没有cache 的情况。
DDR 最大可以有8GB,对所有DDR 存储单元的测试会消耗大量测试时间。因为EDMA 访问效率最高,所以我们可以用EDMA 来做DDR 全空间测试。对其它主模块,如DSP 核,我们不需要用它来访问整个DDR 空间,只需要测试比较小的空间就可以了,目的只是要覆盖从这个主模块到DDR 的数据路径,而DDR 存储单元已经被EDMA 完整的测过了。例如,测试DSP 核通过L2cache 访问DDR,我们只需要测试比L2 cache 大的DDR 空间就可以了,这样就覆盖了数据路径和L2 cache。
本文选自电子发烧友网6月《智能工业特刊》Change The World栏目,转载请注明出处!
3.3 通过不同数据路径测试
由于不同的主模块有自己的总线,同一存储器可以被不同的主模块从不同的数据路径访问。例如,DSP 核和EDMA 通过不同的数据路径访问LL2。
另外,同一主模块也可以通过不同的数据路径访问同一存储器。例如,DSP 核可以通过cache 或不通过cache 访问DDR 存储器。
所有这些不同的数据访问路径都应该被测试程序覆盖。
4 KeyStone DSP 上的示例测试工程
本节介绍上述测试方法在KeyStone DSP 上实现的例子。相应的测试代码可以从以下网址获得:
http://www.deyisupport.com/cfs-file.ashx/__key/telligent-evolution-components-attachments/00-53-01-00-00-10-90-46/Memory_5F00_Test.zip
4.1 CCS 工程
例子工程的目录结构如图2 所示。
图2 例子工程目录结构
工程文件在“Memory_Test”目录中。一些通用的初始化代码,如PLL, EDMA, DDR 的初始化在“common”目录中。主要的测试代码在“Memory_Test\src”子目录中。表2 描述了主要的源文件。
表2 例子代码的源文件
测试流程由“mem_test_main.c”中的代码控制。基本流程如下:
Disable all caches
Test LL2 bus
Test SL2 bus
Test DDR bus
Test Local L1 with IDMA
Test other core’s L1 with EDMA
Enable 32KB L1P cache
Test Local L2 with DSP core
Test other core’s L2 with DSP core
Test Shared L2 with DSP core
Test 1KB of external memory with DSP core (just cover the data path)
Enable 32KB L1D cache
Test Local L2 with EDMA
Test Local L2 with DSP core
Test other core’s L2 with EDMA
Test other core’s L2 with DSP core
Test Shared L2 with EDMA
Test Shared L2 with DSP core
Test external memory with EDMA (cover full external memory space)
Test 64KB of external memory with DSP core (just cover the data path and L1D cache)
Enable 256KB L2 cache
Test other core’s L2 with DSP core
Test 512KB external memory with DSP core (just cover the data path and L1D, L2 caches)
Test Shared L2 with DSP core through remmapped noncacheable nonprefetchable window
本文选自电子发烧友网6月《智能工业特刊》Change The World栏目,转载请注明出处!
4.2 测试配置
测试代码中有多个宏参数可以用来对测试进行配置。
数据测试填充的数值在“DSP_core_mem_test.c”中定义如下。用户可以在这里添加,删除或修改填充的数值。
unsigned long long ulDataPatternTable[ ] = {
0x0000000000000000,
0xffffffffffffffff,
0xaaaaaaaaaaaaaaaa,
0x5555555555555555,
0xcccccccccccccccc,
0x3333333333333333,
0xf0f0f0f0f0f0f0f0,
0x0f0f0f0f0f0f0f0f,
0xff00ff00ff00ff00,
0x00ff00ff00ff00ff
};
本文介绍的三个主要测试算法可以通用以下在“DSP_core_mem_test.c”和“DMA_mem_test.c”中定义的宏开关使能或禁用。“1”表示使能,“0”表示禁用。
#define BIT_PATTERN_FILLING_TEST 1
#define ADDRESS_TEST 1
#define BIT_WALKING_TEST 1
每个存储器都可以通过“KeyStone_mem_test_main.c”中定义的宏开关控制是否被测试。
#define LL1_MEM_TEST 1
#define OTHER_L1_TEST 1
#define LL2_MEM_TEST 1
#define OTHER_L2_TEST 1
#define SL2_MEM_TEST 1
#define EXTERNAL_MEM_TEST 1
是否用DSP 和或DMA 测试存储器也可以通过“KeyStone_mem_test_main.c”中定义的宏开关控制。
#define TEST_BY_DSP_CORE 1
#define TEST_BY_DMA 1
这个测试工程是在TI 的评估板上实现的。如果要在用户真实的板子上运行,需要根据板子的设计在“KeyStone_DDR_Init.c”中修改相应的DDR 参数。PLL 倍频系数也可能需要在调用KeyStone_main_PLL_init()的代码中修改。
要让这些修改后的配置生效,测试工程必须被重新编译。由于测试工程用到了CSL (Chip SupportLibrary)中的头文件,在重编之前可能还需要重新指定CSL 的包含路径。
4.3 测试时间
测试花的时间主要取决于存储器大小,DSP 和存储器速度。表3 列出了本文介绍的所有存储器测试在TI 的评估板(EVM)上测试所花的时间。
表3 在EVM 板上的测试时间
总线测试花的时间只有几百微秒,而存储单元全空间测试花的时间很多。其中,超过90%的时间都花在对DDR 的测试上。
对存储单元的数据测试,地址测试,和走比特测试所花的时间的比例大概是10:1:64,因为数据测试写读了10 个不同的值,地址测试写读了1 个值,而走比特测试写读了64 个值。
用户可以根据测试时间的要求选用不同的测试用例。一般可能有三种组合:
1. 用毫秒级的时间做简单快速的总线测试。
2. 用秒级时间做全存储器空间的基本测试。测试用例包括总线测试和地址测试。
3. 用几分钟甚至几十分钟做全存储器空间的完善测试,执行本文介绍的所有测试用例。
本文选自电子发烧友网6月《智能工业特刊》Change The World栏目