Thread 中讨论的其他器件: C2000WARE
工具与软件:
大家好、团队成员:
我们最近在将 memcpy 函数与快速串行接口(FSI)外设一起使用时遇到一个非预期行为、研究尚未发现任何相关帖子。 我们假设根本原因要么是编译器错误、要么是控制器错误、因此我们要在这里描述该情况。
设置:
控制器:TMS320F28388D
编译器:TI v22.6.1 LTS
CCS:12.6.0.8
C2000WARE:5.1.0.00
项目:
我们使用 timer_ex1_cputimers 示例项目作为 MWe。 未对项目配置和链接器文件进行任何修改。 编译器优化已关闭。
目标:
将数据从 FSI RXA_BUF_BASE 复制到16个字的内部缓冲区。 FSIRXA 缓冲区仍包含来自先前与 MWE 项目无关的测试的数据(不等于0)。 数据被视为有效数据、如下所示:
0x000066C0 0040 0800 0001 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0x000066D2 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0x000066E4 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0x000066F6 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000
方法:
uint16_t dst[16]; memcpy(dst, (void*) 0x66C0, 16); // 0x66C0 is the address of the FSI RX A receive buffer
问题:
dst 缓冲区只包含零、而不包含来自 RX 缓冲区的数据:

要明确的是:这些零由 memcpy 写入、这意味着如果 dst 在 memcpy 之前包含任意数据、则在 memcpy 之后包含16个0。
编译器为特定代码生成的汇编代码如下所示:
memcpy(dst, (void*) 0x66C0, 16); MOVL XAR4, #0x00a800 MOVL XAR7, #0x0066c0 RPT #15 || PREAD *XAR4++, *XAR7
我们通过使用非恒定大小参数找到了该问题的权变措施:
uint16_t dst[16]; volatile int x = 16; // volatile to prevent any optimizations memcpy(dst, (void*) 0x66C0, x);
行为:
数据按预期复制:

编译器生成的汇编代码如下所示:
memcpy(dst, (void*) 0x66C0, x); SETC SXM SPM #0 MOVL XAR5, #0x0066c0 MOVL XAR4, #0x00a800 MOV ACC, *-SP[1] LCR memcpy
因此、使用变通办法时不会生成重复(RPT #15) PREAD 指令。 相反、它分支到 string.h 的 memcpy-implementation、此函 数有效、并且不附带任何生成的 RPT 或 PREAD 指令。
我们进一步分析了这一点、得出的结论是 PREAD 指令导致了该问题。 此外、我们使用重复的 PWRITE 函数编写了一个自己的 memcpy 汇编实现、这个实现显然可行(按预期从 FSI 缓冲区复制数据):
; memcpy 16 words from SRC to DEST ; XAR4 = SRC pointer, XAR5 = DST Pointer, AL = Size _fixed_memcpy: MOVL XAR7, XAR4 SUBB AL,#1 RPT AL || PWRITE *XAR7, *XAR5++ LRETR
由于 编译器生成的 PREAD 指令的行为极易出错、因此我需要了解原因。 我找到了一种可能的解释:
由于 PREAD 定义为将数据值(而不是指令)从程序空间传递到寄存器(参阅 SPRU430F 1.4.2)、因此我假设 FSI 外设不属于程序空间、且/或目标缓冲区不属于数据空间。 因此、我预计在使用 FSI 寄存器作为源代码时、编译器生成的汇编代码无效、这指向编译器错误。
然而,我们还没有清楚的情况。 例如、我们不完全了解它与统一内存模型(在编译器设置中处于活动状态)的关系。 根据我们的理解、在使用统一内存模型时、PREAD/PWRITE 不应有区别、因此我们不清楚为什么 PREAD 不起作用而 PWRITE 起作用。
我们希望向您提出以下问题:
使用 RPT #15 ;|| PREAD *XAR4++,*XAR7 指令如上所示:将零复制到目标的行为是已知的还是预期的? 如果是、为什么会这样? 是否有指定该行为的文档?
从 FSI 数据缓冲区使用具有常量大小的 memcpy 时、编译器是否正确生成 RPT #15;|| PREAD * XAR4++、* XAR7指令?
使用统一内存模型时、PREAD 和 PWRITE 之间是否仍然有任何差异?
该行为是否仅限于 FSI 外设、或者是否可能在任何其他源和/或目标上发生?
该问题如何获得 fixex 或至少避免?
如果您需要任何其他信息、请告知我。 提前感谢!
此致
Felix
