我正在为 PRU-ICSS 器件(AM335x、AM437x、AM57x)、PRU-SS 器件(AM62x)或 PRU_ICSSG 器件(AM24x、AM64x、AM65x)编写 PRU 应用。 我想计算读取或写入需要多少个时钟周期。 我该怎么做?
此常见问题解答是 PRU 阅读延迟应用手册的扩展。 稍后将使用此常见问题解答中的信息更新应用手册。
This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
我正在为 PRU-ICSS 器件(AM335x、AM437x、AM57x)、PRU-SS 器件(AM62x)或 PRU_ICSSG 器件(AM24x、AM64x、AM65x)编写 PRU 应用。 我想计算读取或写入需要多少个时钟周期。 我该怎么做?
此常见问题解答是 PRU 阅读延迟应用手册的扩展。 稍后将使用此常见问题解答中的信息更新应用手册。
PRU 读写指令
处理器内核通过执行指令来工作。 即使 PRU 固件是用 C 语言编程的、C 编译器也会将 C 代码转换为 PRU 内核可以运行的指令。 为了直接控制在 PRU 内核上运行的每条指令、PRU 固件也可以采用汇编语言编写。 如果应用关心的是读取是在6个 PRU 时钟周期还是7个 PRU 时钟周期内执行、则时间敏感代码可能应以汇编语言编写。
本文档将使用术语"延迟"来描述执行指令所需的时间。
完整的 PRU 指令集记录在 PRU 汇编指令用户指南中。 该文档列出了三种读取和写入指令:
LBBO (加载字节突发)和 SBBO (存储字节突发)
LBBO 和 SBBO 是默认的读(即加载)和写(即存储) PRU 指令。 本常见问题解答将重点介绍如何使用 LBBO 和 SBBO 计算读写延迟。
LBCO (具有恒定表偏移的负载字节突发)和 SBCO (具有恒定表偏移的存储字节突发)
LBCO 和 SBCO 的工作方式与 LBBO 和 SBBO 类似。 但是、LBCO 和 SBCO 使用 PRU 常量表中的地址、而不是使用寄存器来指定读/写存储器地址。 LBCO 和 SBCO 的执行延迟与 LBBO 和 SBBO 的延迟相同。
虽然只执行读取或写入的延迟相同、但 LBCO/SBCO 总体占用的时钟周期更少。 由于 LBBO/SBBO 的读取/写入地址存储在寄存器中、LBBO/SBBO 需要额外的汇编指令来将地址加载到寄存器中。 由于 LBCO 和 SBCO 使用常数表条目代替寄存器值来读取/写入地址、因此 LBCO 和 SBCO 不需要额外的"地址加载"汇编指令。
宽边命令:XIN (寄存器传输输入)、XOUT (寄存器传输输出)、xchg (寄存器交换)
TODO:PRU_ICSSG 器件是否支持 xchg? 汇编指令用户指南指示 AM335x 不支持 xchg
XIN 和 XOUT 可用于向宽边接口读取或写入多达31个寄存器。 由于 XIN 和 XOUT 在单个 PRU 时钟周期内执行、因此它们是移动数据的最快方式。 但是、XIN 和 XOUT 只能与连接到宽边接口的模块通信。
不同的 PRU 器件具有不同的宽边接口附件。 例如、AM335x 可以使用 XIN 和 XOUT 在 PRU 内核和暂存区寄存器之间移动寄存器、或直接从一个 PRU 内核移动到另一个 PRU 内核。 AM64x 可以使用 XIN 和 XOUT 将信息移动到暂存区寄存器或从暂存区寄存器移动信息、但不能直接移动到另一个 PRU_ICSSG 内核。 但是、AM64x 还可以使用 XIN 和 XOUT 访问其自己的专用宽边(BS) RAM、或通过 XFR2VBUSP 接口将多个寄存器读取并写入 PRU_ICSSG 外部的存储器空间。 如需更多信息、请参阅所需处理器的技术参考手册(TRM)。
本 常见问题解答中不讨论宽边命令。
如何判断读取还是写入是确定性的?
PRU 内核是完全确定的。 这意味着我们可以准确知道每条 PRU 指令执行所需的时间...但有一些例外、如下所述。
非读写指令
不是读取或写入的 PRU 指令是完全确定的。 这些指令将始终只需一个 PRU 时钟周期即可执行。
将指令读写到 PRU 子系统中的某个地址
读取和写入 PRU 子系统中的地址是完全确定的。 但是、还需要一些额外的数学运算:
读或写指令需要多长时间、有具体的规则。 我们将在下面深入介绍这些规则。
但是 、如果 PRU 内核尝试访问 PRU 子系统中的外设、而另一个内核已在对该外设进行读取或写入、该怎么办? 或者、如果两个内核尝试在完全相同的时钟周期访问同一个外设、该怎么办? 一次只能有一个内核访问外设、因此 PRU 子系统会在两个内核之间进行仲裁、以确定哪个内核优先。 一旦一个内核正在读取或写入外设、第二个内核将在外设可用之前停止。 失速时间被称为"仲裁延迟"。
在设计具有敏感时序的 PRU 系统时、设计人员必须牢记可能的最低延迟(即"执行读取/写入的时间")和可能的最高延迟(即"执行读取/写入的时间"+"仲裁延迟")。
将指令读写到 PRU 子系统之外的系统地址
读取和写入 PRU 子系统之外的地址不是确定性的。 可能存在扼流点、仲裁延迟、其他内核的影响等。但是、您仍然可以通过执行测试来估算外部读取和写入的延迟。
当信号退出 PRU 子系统时、PRU-ICSS 内核和 PRU-SS 内核将不会经历仲裁延迟(尽管 LBBO 命令仍可能受系统其他部分的仲裁延迟的影响)。 但是、PRU_ICSSG 访问外部系统 时必须考虑仲裁延迟。
使用 SBBO 计算写入延迟
PRU-ICSS/PRU-SS 写入 PRU 子系统外的存储器位置:n 个 PRU 时钟写入 N 个字
这些说明是"发射后不管"的。
PRU 子系统和器件其余部分之间有缓冲器。 SBBO 需要 N 个时钟周期才能将 N 个字写入系统总线缓冲区。 然后、PRU 将移至下一个汇编命令、而无需等待写入完成。 写入缓冲区的值需要额外的时间才能通过系统总线传输、并最终更新外部存储器地址。
这假定 SBBO 写入的地址是字对齐的地址(例如0x100、0x104、0x108等)。 每当加载超过4字节边界时、它需要另一个 PRU 时钟周期。
例如、将2个字节写入0x100:一个 PRU 时钟
例如、将2个字节写入0x102:一个 PRU 时钟
例如、将2个字节写入0x103:2个 PRU 时钟(一个时钟写入0x100处的字、一个时钟写入0x104处的字)
*因此、如果写入地址不是字对齐的、则公式更改为 N + 1 PRU 时钟、以便 SBBO 写入 N 个32位字
PRU_ICSSG 写入 PRU 子系统外部的存储器位置:n 个 PRU 时钟写入 N 个字、外加每片仲裁延迟
请参阅上面的 PRU-ICSS/PRU-SS 部分和下面的仲裁延迟部分。
PRU-ICSS/PRU-SS 写入 PRU 子系统中的存储器位置:n 个 PRU 时钟用于写入 N 个字、外加仲裁延迟
PRU 内核和 PRU 子系统内部的存储器之间没有缓冲器。 因此、如果另一个内核正在使用连接到 ICSS CBASS 总线 的端点、PRU 内核必须等待该端点变为可用、然后才能执行写操作。
内部 CBASS 互连是"完全开关"的。 这意味着、只要内核访问不同的端点、多个内核就可以同时使用 CBASS。例如、PRU0可以在 PRU1访问 PRU 的硬件 UART 的同时访问 DRAM。
有关如何计算仲裁延迟的信息、请参阅下面的"深入探讨仲裁延迟"一节。
此处适用相同的字对齐规则。即、如果写入不是字对齐、则添加1个额外的时钟周期。
PRU_ICSSG 写入 PRU 子系统中的存储器位置:n 个 PRU 时钟用于写入 N 个字、外加仲裁延迟
请参阅上面的 PRU-ICSS/PRU-SS 部分。 请注意、每个 ICSSG 只有一个内部 CBASS。 因此、如果内核同时尝试访问同一 个端点 、则不同片中的内核仍将处理仲裁延迟。
使用 LBBO 计算读取延迟
PRU-ICSS / PRU-SS 读取:读取指令需要多个 PRU 时钟周期、具体取决于目标 地址 在处理器上的距离。 从 PRU 子系统内的存储器位置读取可能具有仲裁延迟。
请参阅下面的"有关 LBBO 和 DRAM 的深入探讨"部分。
SBBO 中的相同字对齐规则适用于此处。即、如果读取不是字对齐、则添加1个额外的时钟周期。
PRU_ICSSG 读取:读取指令需要多个 PRU 时钟周期、具体取决于目标 地址在 处理器上的距离。 从 PRU 子系统内的存储器位置读取可能具有仲裁延迟。 从 PRU 子系统外的存储器位置读取数据可能具有 每片仲裁延迟
请参阅下面的仲裁延迟部分。
深入了解 LBBO 和 DRAM
来自 PRU DRAM 的 LBBO 需要2 + N 个 PRU 时钟来读取 N 个字 (加上仲裁延迟、如果地址不是字对齐、则加上1个 PRU 时钟)
LBBO 需要3个时钟周期从 PRU 内部存储器获取前4个字节的数据。 每增加4个字节、就会增加1个时钟。
例如 、LBBO loadDestination、loadAddress、0、16
需要6个 PRU 时钟:3个时钟加载前4个字节、3个时钟加载后12个字节
仲裁延迟和 PRU 总线结构
PRU 总线结构:PRU-ICSS、PRU-SS
PRU 子系统具有内部 CBASS (也称为 VBUSM)。 每个 PRU 内核都可以直接连接到内部 CBASS 和系统 CBASS。 对外部 CBASS 的访问与对内部 CBASS 的访问完全分开。 这意味着通过内部 CBASS 进行的读取或写入不受通过外部 CBASS 进行的读取或写入的影响。
VBUSM 互连是"完全交换的"。 这意味着、只要内核访问不同的端点、多个内核就可以同时使用 CBASS。例如、PRU0可以在 PRU1访问 PRU 的硬件 UART 的同时访问 DRAM。 端点可以是外设、也可以是存储器。 独立存储器充当独立的端点(例如、一个内核可以访问 DMEM0、一个内核可以访问 DMEM1、另一个内核可以同时访问 SRAM)。
PRU 总线结构:PRU_ICSSG
除了 PRU-ICSS 上的 CBASS 接口外、PRU_ICSSG 在每个 ICSSG 层和外部 CBASS 层之间还有一个 VBUSP。 VBUSP 与 VBUSM 不同、因为 VBUSP 一次只能由一个内核使用。
内部 CBASS 仲裁
只要 PRU 内核从内部 CBASS 中的某个端点执行加载或存储(即读取或写入)、就有可能有另一个内核正在访问该端点。
内部 CBASS 总线为4字节宽。 这适用于所有 PRU 器件。 因此、如果另一个内核执行 x 个字节的原子写入、则需要 ceil (x/4) PRU 时钟才能进行写入。 例如、写入30个字节将需要 ceil (30/4)= ceil (7.5)= 8个 PRU 时钟才能完成。
如果 PRU 内核和非 PRU 内核(例如 Linux A53或 RTOS R5)尝试在 同一 PRU 时钟周期(SRAM、UART、ECAP 等)内访问相同的 PRU 子系统位置、则 PRU 将胜出。 但是、如果 PRU 在另一个内核执行猝发写入事务后从 SRAM 发起事务、则 PRU 事务将在猝发写入完成前挂起。 因此、如果非 PRU 内核的写入操作需要8个 PRU 时钟才能完成、则 PRU 必须等待的最长时间为8 - 1 = 7个 PRU 时钟。 如果您希望完全避免仲裁延迟、可以对非 PRU 内核进行编程、以执行多个4字节写入、而不是单个长写入。 在这种情况下、PRU 将在发起读取的每个时钟周期赢得仲裁。
PRU-ICSS、PRU-SS: 如果两个 PRU 内核在同一 PRU 时钟周期内尝试访问相同的 PRU 子系统位置、则 PRU0胜出(DMEM1除外、其中 PRU1胜出)。
PRU_ICSSG: 如果多个内核尝试在同一 PRU 时钟周期内访问相同的 PRU 子系统位置、则优先级更高的内核将会胜出。 内核按最高优先级到最低优先级顺序列出:PRU_TX0 > PRU_TX1 > PRU0 > PRU1 > RTU0 > RTU1。
到外部 CBASS 的仲裁(只适用于 PRU_ICSSG)
PRU-ICSS 和 PRU-SS 内核在尝试访问外部系统 CBASS 时不会遇到仲裁延迟。
每个 PRU_ICSSG 层都有一个扼流点、其中 PRU、RTU 和 TX_PRU 都连接到同一个 VBUSP、该 VBUSP 连接到外部 CBASS。 因此、如果片中的一个内核通过 VBUSP 读取或写入外部 CBASS、片中的其他内核在 VBUSP 可用之前无法访问外部 CBASS。 到外部 CBASS 的接口为4字节宽、所以计算到外部 CBASS 的仲裁延迟的数学方法与计算到内部 CBASS 的仲裁延迟的数学方法是一样的。 有关如何计算原子读取或写入的仲裁延迟、请参阅"内部 CBASS "关于仲裁延迟的讨论。
如果多个 PRU_ICSSG 内核尝试以完全相同的时钟周期访问外部 CBASS、则仲裁优先级为:首先是 TX_PRU、然后是 PRU、再是 RTU。
层之间没有阻滞点。例如、如果 ICSSG1_PRU0正在使用外部 CBASS、则 ICSSG1_PRU1不受仲裁延迟的影响、因为它位于单独的层中。