C语言 在 ARM 上进行高效复制,两个 16 位提取或 1 个 32 位



我正在使用ARM7TDMI处理器开发嵌入式系统。

在时间紧迫的 ISR 中,我需要将 24 个 16 位值从硬件寄存器快照(复制)到 SRAM 中。 这些值是连续的,可以被视为数组。

数据总线(到SRAM和硬件寄存器)是16位的,我们在ARM模式(8/32)下运行。

在商店中,我们正在讨论复制数据的最佳方法:作为 16 位数量或作为 32 位数量。

我的论点是 ARM 处于 32 位模式,因此它用一条指令进行 2 次 16 位提取比用两条 16 位指令分别进行一次获取要快。
此外,要获取的指令数量只有一半,这应该将时间减少 1/2。

有人有任何数据支持这两种方法吗?(我的O示波器都已分配,因此我无法在嵌入式系统上进行测量。 由于 ISR 每毫秒中断一次,也无法运行大量次数。*(分析很困难,因为我们的JTAG喷射探头不能提供准确分析的方法)。

示例代码 - 16 它复制:

#define MAX_16_BIT_VALUES 24U
uint16_t volatile * p_hardware;
uint16_t data_from_hardware[MAX_16_BIT_VALUES];
data_from_hardware[0] = p_hardware[0];
data_from_hardware[1] = p_hardware[1];
data_from_hardware[2] = p_hardware[2];
data_from_hardware[3] = p_hardware[3];
//...
data_from_hardware[20] = p_hardware[20];
data_from_hardware[21] = p_hardware[21];
data_from_hardware[22] = p_hardware[22];
data_from_hardware[23] = p_hardware[23];

示例代码,32 位副本:

uint32_t * p_data_from_hardware = (uint32_t *)&data_from_hardware[0];
uint32_t volatile * p_hardware_32_ptr = (uint32_t volatile *) p_hardware;
p_data_from_hardware[0] = p_hardware_32_ptr[0];
p_data_from_hardware[1] = p_hardware_32_ptr[1];
p_data_from_hardware[2] = p_hardware_32_ptr[2];
p_data_from_hardware[3] = p_hardware_32_ptr[3];
//...
p_data_from_hardware[ 8] = p_hardware_32_ptr[ 8];
p_data_from_hardware[ 9] = p_hardware_32_ptr[ 9];
p_data_from_hardware[10] = p_hardware_32_ptr[10];
p_data_from_hardware[11] = p_hardware_32_ptr[11];

详细信息:ARM7TDMI处理器以 8/32 位模式运行,IAR EW 编译器。

注意:展开代码是为了防止指令缓存重新加载。
注: 程序集语言列表显示,使用常量索引的访问内存比通过递增指针更有效。

编辑1:测试

根据Chris Stratton的评论,我们在16位FPGA寄存器上进行32位提取时遇到了问题,因此无法进行32位优化。

也就是说,我使用 DMA 进行了分析。 使用 DMA 控制器的性能提升为 30 us(微秒)。 在我们的项目中,我们希望节省更多的时间,因此这种优化是不值得的。 这个实验表明,如果我们有更多的数据要传输,或者传输可以并行,DMA 将非常有用。

一个有趣的说明是,DMA需要17条指令才能设置。

如果速度是最重要的,那么如果硬件可以支持它,最好的选择将是汇编语言例程,如下所示:

; Assume R0 holds source base and R1 holds destination base
PUSH   {R4-R7}
LDMIA R0,{R2-R7}
STMIA R1,{R2-R7}
LDMIA R0,{R2-R7}
STMIA R1,{R2-R7}
POP    {R4-R7}

我相信ARM7TDMI,当使用32位总线时,LDR需要三个周期,STR需要两个周期;使用LDRMIA/STRMIA加载或存储n个单词需要3+n个周期。 因此,12 个 LDR 和 12 个 STR 将需要 60 个周期,但上述序列需要 50 个周期(包括寄存器保存/恢复)。 我希望使用 16 位总线会为每个 32 位加载或存储增加额外的周期损失,但如果 LDM* 和 STM* 指令将每个 32 位操作拆分为两个 16 位操作,它们仍然应该比离散加载和存储快得多,特别是如果代码必须从 16 位内存中获取。

最新更新