背景
我一直在研究可能将MPC5200静态 ram 空间用作暂存器内存。我们有 16Kb 的未使用内存出现在处理器总线(源)上。
现在一些重要的实现说明是:
该内存由BestComm DMA控制器使用,在
RTEMS
此之下将在 SRAM 的开头设置一个任务表,其中包含一组 16 个任务,可以作为外围接口、I2C、以太网等的缓冲区运行。为了使用这个空间没有冲突并且知道我们的系统只使用了大约 2Kb 的以太网驱动程序缓冲区,我将 SRAM 的开始偏移了 8Kb,所以现在我们有 8Kb 的内存,我们知道系统不会使用它。RTEMS
定义一个指向静态内存的数组,如下所示:
(来源)
typedef struct {
...
...
volatile uint8_t sram[0x4000];
} mpc5200_t;
extern volatile mpc5200_t mpc5200;
而且我知道 sram 数组指向静态内存,因为当我编辑第一部分并打印出内存块(MBAR + 0x8000
源)时
所以从这里我可以说以下内容,我有 RTEMS 定义的对SRAM
via的访问mpc5200.sram[0 -> 0x2000]
。这意味着我可以开始对我可以摆脱它的速度进行一些测试。
测试
为了评估速度,我设置了以下测试:
int a; // Global that is separate from the test.
**TEST**
// Set up the data.
const unsigned int listSize = 0x1000;
uint8_t data1[listSize];
for (int k = 0; k < listSize; ++k) {
data1[k] = k;
mpc5200.sram[k] = k;
}
// Test 1, data on regular stack.
clock_t start = clock();
for (int x = 0; x < 5000; ++x) {
for (int y = 0; y < 0x2000; ++y) {
a = (data1[y]);
}
}
double elapsedTime = static_cast<double>(clock() - start) / CLOCKS_PER_SEC;
printf("elapsed dynamic: %f\n" ,elapsedTime);
// Test 2, get data from the static memory.
start = clock();
for (int x = 0; x < 5000; ++x) {
for (int y = 0; y < 0x2000; ++y) {
a = (mpc5200.sram[y]);
}
}
elapsedTime = static_cast<double>(clock() - start) / CLOCKS_PER_SEC;
printf("elapsed static: %f\n" ,elapsedTime);
非常简单,概念是我们正在迭代可用空间并设置全局。我们应该期望静态内存应该有相同的近似时间。
结果
所以我们得到以下信息:
elapsedDynamic = 1.415
elapsedStatic = 6.348
所以这里发生了一些事情,因为静态几乎比缓存慢 6 倍。
假设
所以我对为什么会这样有 3 个想法:
- 缓存未命中,我想也许是因为我们正在混合动态和静态 ram,所以发生了一些奇怪的事情。所以我尝试了这个测试:
.
// Some pointers to use as incrementers
uint8_t *i = reinterpret_cast<uint8_t*>(0xF0000000+0x8000+0x1000+1);
uint8_t *j = reinterpret_cast<uint8_t*>(0xF0000000+0x8000+0x1000+2);
uint8_t *b = reinterpret_cast<uint8_t*>(0xF0000000+0x8000+0x1000+3);
// I replaced all of the potential memory accesses with the static ram
// variables. That way the tests have no interaction in terms of
// memory locations.
start = clock();
// Test 2, get data from the static memory.
for ((*i) = 0; (*i) < 240; ++(*i)) {
for ((*j) = 0; (*j) < 240; ++(*j)) {
(*b) = (mpc5200.sram[(*j)]);
}
}
elapsedTime = static_cast<double>(clock() - start) / CLOCKS_PER_SEC;
printf("elapsed static: %f\n" ,elapsedTime);
我们有以下结果:
elapsedDynamic = 0.0010
elapsedStatic = 0.2010
所以现在它慢了 200 倍?所以我想这与此无关?
与正常不同的静态内存,我想到的下一件事是,由于这条线,它可能不会像我想象的那样交互:
MPC5200 包含 16KBytes 的片上 SRAM。BestComm DMA 单元可以直接访问该内存。它主要用作任务表和缓冲区描述符的存储,BestComm DMA 使用它来将外设数据移入和移出 SDRAM 或其他位置。这些描述符必须在启动时下载到 SRAM。该 SRAM 位于 MPC5200 内部寄存器空间中,也可由处理器内核访问。因此,它可以用于其他目的,例如便签本存储。16kBytes SRAM 从位置 MBAR + 0x8000 开始。
(来源)
我不确定如何确认或否认这一点?
- 较慢的静态时钟,也许静态内存运行在较慢的时钟上,就像在某些系统中一样?
这可以通过查看手册来反驳:
(来源)
SRAM 和处理器在同一个时钟上,XLB_CLK
以处理器基频运行(来源)
问题
什么可能导致这种情况,一般有理由不使用 SRAM 进行暂存器存储吗?我知道在现代处理器上这甚至不会被考虑,但这是一个较旧的嵌入式处理器,我们正在为速度和空间而奋斗。
额外测试
所以在下面的评论之后,我进行了一些额外的测试:
- 添加
volatile
到堆栈成员以查看速度是否更相等:
.
elapsedDynamic = 0.98
elapsedStatic = 5.97
所以仍然快得多,并且与volatile没有任何变化??
- 反汇编代码看看发生了什么
.
// original code
int a = 0;
uint8_t data5[0x2000];
void assemblyFunction(void) {
int * test = (int*) 0xF0008000;
mpc5200.sram[0] = a;
data5[0] = a;
test[0] = a;
}
void assemblyFunction(void) {
// I think this is to load up A
0: 3d 20 00 00 lis r9,0
8: 80 09 00 00 lwz r0,0(r9)
14: 54 0a 06 3e clrlwi r10,r0,24
mpc5200.sram[0] = a;
1c: 3d 60 00 00 lis r11,0
20: 39 6b 00 00 addi r11,r11,0
28: 3d 6b 00 01 addis r11,r11,1 // Where do these come from?
2c: 99 4b 80 00 stb r10,-32768(r11)
test[0] = a;
c: 3d 20 f0 00 lis r9,-4096 // This should be the same as above??
10: 61 29 80 00 ori r9,r9,32768
24: 90 09 00 00 stw r0,0(r9)
data5[0] = a;
4: 3d 60 00 00 lis r11,0
18: 99 4b 00 00 stb r10,0(r11)
我不是特别擅长互穿汇编程序,但也许我们这里有问题?从全局访问和设置内存似乎需要更多的指令SRAM
?
- 从上面的测试看来,指针的指令较少,所以我添加了这个:
.
uint8_t *p = (uint8_t*)0xF0008000;
// Test 3, get data from static with direct pointer.
for (int x = 0; x < 5000; ++x) {
for (int y = 0; y < 0x2000; ++y) {
a = (p[y]);
}
}
我得到以下结果:
elapsed dynamic: 0.952750
elapsed static: 5.160250
elapsed pointer: 5.642125
所以指针需要更长的时间!我会认为它会完全一样?这只是越来越陌生。