Other Parts Discussed in Thread: LP-AM243, SYSCONFIG
器件型号: LP-AM243
#`tiesc_memcpy`严格排序的 PRU-ICSS 共享 RAM +用于重建 SDK 库的打包枚举 ABI 的安全性
**平台:** AM243x (LP-AM243)
** SDK:** MCU+ SDK 11.01.00.19、工业通信 SDK 2025.00.00.08
**编译器:** ARM 编译器 6 (armclang v6, ARM Development Studio 2025.0)
**应用:** Cortex-R5F、NoRTOS 上的 EtherCAT 子器件 (Beckhoff SSC)
——
##观察 1:所有预构建的 EtherCAT `.lib`文件都使用打包的枚举
`~/ti/ind_comms_sdk_am243x_2025_00_00_08`中附带的所有 EtherCAT`.lib`文件均使用打包枚举进行编译 (` ABI_ENUM_SIZE:packed `):
|库|路径|
|----- |----- |
|`EtherCAT_subdevice_ICSS_fwhal`|`……/EtherCAT_subdevice/ICSS_fwhal/lib/`|
|`ethercat_subdevice_lwip_fretos`|`……/ethercat_subdevice/stack/lwip/lib/`|
|`EtherCAT_subdevice`|`……/EtherCAT_subdevice/stack/lib/`|
`|` EtherCAT_iolink_gateway `|`.../EtherCAT_iolink_gateway/stack/lib/ |
与这些引脚相链接的任何代码也必须使用`-fshort-enums`以避免 ABI 不匹配。
——
##观察 2:PRU-ICSS 共享 RAM 是严格排序的存储器
SysConfig 生成的 MPU 配置 (`ti_DPL_config.c`)、用于 EtherCAT 子器件演示:
```c
//区域 0:涵盖 0x00000000 - 0x7FFFFFFF (2GB)
{
.baseAddr = 0x0u、
.size = MpuP_RegionSize_2G、
.attrs ={
.isCacheable = 0、
.isBufferable = 0、
.tex = 0、 // TEx=0、C=0、B=0 ->严格排序 (ARMv7-R)
...
}、
}、
```μ s
无较高优先级的区域覆盖`0x30090000`。 ESC 寄存器实时位于:
```μ s
CSL_PRU_ICSSG1_DRAM0_SLV_RAM_BASE (0x30080000)+ PRUICSS_SHARED_RAM (0x10000)
= 0x30090000 + ESC_OFFSET
```μ s
——
`观察 3:在任意字节偏移处、` tiescbsp.c `m通过` emcpy 访问 ESC 寄存器
```c
// tiescbsp.c 行 111:
void * tiesc_memcpy (uint8_t *dst、const uint8_t * src、uint32_t size_bytes)
{
memcpy (dst、src、size_bytes); //直接委托给 libc memcpy
返回 DST;
}
// tiescbsp.c 行 2438 (bsp_read):
uint8_t *PESC =(uint8_t *)(pruIcssHandle->hwAttrs->baseAddr + PRUICSS_shared_RAM);
tiesc_memcpy (pdata、&PESC[ADDRESS]、len); // address 可以是任何 ESC 偏移量(例如 0x0802)
```μ s
——
##观察 4:TI` tiarmclang `mlibc `emcpy32.S` behavior
从`armv7r-ti-none-eabi/c/libc.a 拆卸`:
```ASM
<_unaln>: ;在 src & 3!= 0 时输入
C4:ldrb R3、[R1]、#1 ;字节读取在 src
C8:strb R3、[r0]、#1
CC:SUB R2、R2、#1
D4:TST R1、#3 ; src word-aligned 还没有?
D8:BNE _unaln ;循环直至对齐
<_aln> -> <_c16>: ;一旦 src 被字对齐
2C:LDM R1!、{R3、R4、IP、LR} ; 16 字节批量字对齐加载
30:STM r0!、{R3、R4、IP、LR}
<_1line> 尾(剩余 1-3 个字节):
94:ldrb r3、[r1]、#1 ;剩余 1 个字节
A0:ldrh r3、[r1]、#2 ;剩余 2 个字节(半字对齐)
b0:ldrh + ldrb ;剩余 3 个字节
```μ s
键属性:
-字节 — 仅向前复制,直到`src`达到字对齐—在`src`之前永远不会读取
-`加载 (` LDM`/` LDR `) 只发生在 src`[LDM、src + len ) 内的自然对齐的地址上
- Tail 在半字对齐地址使用`LDRH`,单个字节使用`LDRB`
——
##观察 5: ARM 编译器 6 `memcpy`存在严重差异
从 ARM 编译器 6 `libc.a`(`armv7r_hard_vfpv3_D16`) 进行反汇编:
```ASM
B8:SUB IP、R1、R4 ; IP = src 向下对齐(在 src 之前!)
C8:LDR R5、[IP] ;在请求的 src 之前从读取的 32 位
d0:LDR R6、[IP、#4]! ;下一个字
E8:ORR R1、R1、R5、LSR R4 ;桶形移位以提取目标字节
```μ s
该字将源指针**向下对齐**并在请求的地址之前读取存储器**以填充寄存器、然后使用桶形移位来提取目标字节。 在严格排序的器件存储器上、这会访问调用方从未预期过的 ESC 寄存器—可能会触发读取副作用或总线错误。
——
##观察 6:我们使用 ARM 编译器的权变措施 6.
我们使用 per-TU 编译标志重定向`mtiescbsp.c`的`emcpy`对逐字节`volatile uint8_t*`实现的调用:
```cmake
set_source_files_properties (
${ICSS_FWHAL_base}/tiescbsp.c
属性 compile_flags
“-memcpy=tiescbsp_safe_memcpy -dmemset=tiescbsp_safe_memset“
)
```μ s
这在对严格排序存储器进行任何对齐时都是安全的。
——
##问题
** Q1(`枚举):**如果客户需要从源代码重新编译 MCU+ SDK 和工业通信 SDK 中的所有 TI 库、是否应使用`-fshort-enum`/`-mshort-enums 重建这些库? 这是否记录在任何地方?
** Q2(存储器访问宽度):** PRU-ICSS 共享 RAM (EtherCAT ESC 寄存器空间为`0x30090000`) 是支持完整 32 位的存储器吗? 在 TI 的`memcpy32`将`src`对齐到字边界后、它会执行`LDM`/`LDR`(32 位)读取。 这对于所有 ESC 寄存器偏移是安全的、还是仅因为实际中的 ESC 访问恰好是字对齐和字大小才起作用?
** Q3(半字访问):**在所有半字对齐的 ESC 寄存器偏移量上`LDRH`(半字加载)是安全的吗? 当保留 2 个字节时、TI 的`memcpy32 `尾路径使用` ldrh R3、[R1]、#2`。
*** Q4 (`tiesc_memcpy` contract ):***` tiesc_memcpy `应该提供一个字节安全的实现,而不是委派给`memcpy ()`? 如果合约在任意 ESC 偏移量下安全访问严格排序的 PRU-ICSS 存储器、则此函数本身不应该使用逐字节访问(类似于 TI 的`libc.a`中已经存在的`TI_memcpy_small`)?
** Q5(ARM 编译器 6 指导):**对于使用 ARM 编译器 6 而不是`tiarmclang`的客户、TI 是否有一种推荐的方法? ARM 的`memcpy`在源地址之前读取(桶式移位器优化)。 我们当前的权变措施是 per-TU`-dmemcpy=`on ` tiescbsp.c`。 这是预期模式、还是有支持的替代模式?