Renesas-RH850 CPU System - Mutual Exclusion

Renesas学习笔记
CPU System : Mutual Exclusion


该 CPU 提供的指令使系统在多处理环境下运行时,可以从多个程序中互斥地控制共享资源。

注意:单处理器配置中的嵌入式 CPU 使用通过禁用可屏蔽中断确认来维护数据一致性编程模型。这是一种非常简单且可靠的方法,但在多处理器中,多个程序可能同时执行并尝试使用数据。在这种情况下,仅通过禁用可屏蔽中断确认无法维护数据一致性。

1 互斥概述

本地 RAM 和集群 RAM 可用作独占控制的资源。作为原子操作指令,LDL/STC、CAXI、SET1、CLR1 和 NOT1 指令可以在本地 RAM 和集群 RAM 上执行。这些寄存器也可以通过 LD 和 ST 指令访问,但不被视为原子操作。

2 互斥功能
2.1 不需要互斥处理的共享数据

即使在多处理器环境中,该 CPU 也能维护以下类型的数据访问的一致性:

  • 数据对齐至与数据类型匹配的大小(对齐访问)——LD、ST、SLD、SST、LDL、STC 和位操作指令 (TST1)
  • 使用位操作指令(SET1、CLR1 或 NOT1)进行的访问(读-改-写)
  • 使用 CAXI 指令进行的访问(读-改-写)

注意:指令是否原子执行取决于数据格式。请参见第 3.2.2.6 节,数据类型。

在某些例外情况下,使用这些类型的数据访问实现互斥。换句话说,可以保证在一个 CPU 执行上述数据访问的指令时,另一个 CPU 不会访问这些数据。这称为指令的原子执行或指令保证原子性。

请注意,指令的原子执行意味着数据访问总线事务完成而不受干扰;这不一定意味着一系列事务已完成。

注意:根据硬件规格,不同内存的情况,不保证使用对齐访问可以保证一致性。详见第 3.5.1 节,互斥概述和第 3.9.3 节,通过位操作指令访问寄存器。

2.2 LDL 和 STC 指令的操作

LDL 和 STC 指令可用于在多核系统更新内存时获得准确处理的原子读-改-写操作。这些指令的操作如下。有关 LDL 和 STC 指令的操作,请参见《RH850G4MH 用户手册:软件》。

(1)链接(Link) :每个 CPU 只能创建一个链接(LLbit)。链接包括创建它的地址信息,并根据在该地址执行的 STC 指令的成功或失败以及链接是否丢失进行控制。链接还包括创建链接时的数据大小信息,因此任何与创建链接的 LDL 指令数据大小不同的 STC 指令总是会失败,并且链接将被删除。

(2)链接生成(Link generation): 每个 CPU 都能够生成到本地 RAM 和集群 RAM 的链接。对目标 RAM 执行 LDL 指令,会将链接地址注册、设置链接标志,并响应指令读取生成链接。

  • (a)给定处理器的本地 RAM
  • (b)集群 RAM

每个CPU都能够生成到(a)或到(b)的链路

(3)存储成功(Success in storing): 在生成链接后,仅在执行对应生成链接的 STC 指令时才会进行存储。

(4)存储失败(Failure in storing): 如果链接丢失,即使处理了相应地址的 STC 指令也不会进行存储。如果处理了与链接不对应的 STC 指令,也不会进行存储。

(5)存储成功的条件(Condition for successful storing): 如果满足以下条件,则 STC 指令被判定为对应链接的地址。

  • 生成链接的 LDL 指令的地址和大小与 STC 指令的地址和大小匹配。

(6)链接的丢失(Loss of the link): 当满足某些事件或地址条件时,链接会丢失。下表显示了链接丢失条件。如果满足此表中显示的任何条件,则链接会丢失。

事件条件 备注
对包含现有链接地址的 32 字节对齐地址范围进行存储操作*1 这适用于生成链接的 CPU 和其他总线主设备(例如 CPU)的以下操作:
- ST、SST、STC 和 STV 指令
- SET1、NOT1、CLR1 和 CAXI 指令
- PREPARE、PUSHSP 和 STM.MP 指令
在其自身 CPU 中对与现有链接对应的位置执行 STC 指令 无论指令的结果是成功还是失败,相应的链接(上述 (1) 或 (2))都会丢失。
在其自身 CPU 中对与现有链接对应的位置执行 LDL 指令 CPU 响应其前一 LDL 指令生成的链接将丢失,并生成响应后续 LDL 指令的链接。
执行 CLL 指令
异常确认
执行 EIRET 指令
执行 FERET 指令
LDL 的总线访问错误

注意 *1:在本地 RAM 中,如果执行除 STC/CAXI 指令以外的存储指令,链接并不总是会丢失。因此,使用不需要这些指令导致链接丢失的程序流程。例如,在示例代码 (7) 中,在使用 LDL 指令读取锁变量后,仅在没有人持有锁时执行 STC 指令,程序流程不需要因存储指令释放锁而导致的链接丢失。

(7)示例代码
以下显示了使用 LDL.W 和 STC.W 指令执行的自旋锁示例代码。

锁获取:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
 MOV lock_adr, r20
Lock:
LDL.W [r20], r21
CMP r0, r21
BNZ Lock_wait
MOV 1, r21
STC.W r21, [r20]
CMP r0, r21
BNZ Lock_success
Lock_wait:
SNOOZE
BR Lock
Lock_success:
ST.W r0, 0[r20]

锁释放

1
ST.W r0, 0[r20]
2.3 使用 SET1 指令执行互斥

SET1 指令可用于在多个数据数组上执行互斥。通过在内存中的相同位上执行 SET1 指令,然后检查指示执行结果的 PSW.Z 标志,可以确定锁获取是否成功。

注意:

  • 1 根据硬件规格,如果使用 SET1 指令频繁执行独占控制,系统性能可能会下降,因为这会长时间占用总线。因此,建议尽可能使用 LDL/STC 指令执行独占控制。
  • 2 当使用 SET1 指令执行互斥时,为防止上述注意事项 1 中描述的总线占用过多的问题,在锁获取失败后再次尝试获取锁之前执行 SNOOZE 指令,并调整锁获取循环执行间隔。

示例代码,以下显示了使用 SET1 指令执行的自旋锁示例代码。

锁获取

1
2
3
4
5
6
7
 MOV lock_adr, r20
Lock:
SET1 0, 0[r20]
BZ Lock_success
SNOOZE
BR Lock
Lock_success:

锁释放

1
CLR1 0, 0[r20]
2.4 使用 CAXI 指令执行互斥

CAXI 指令可用于在多个数据数组上执行互斥。通过在内存中的相同字上执行 CAXI 指令,然后检查目标寄存器,可以确定锁获取是否成功。

注意:

  • 1 根据硬件规格,如果使用 CAXI 指令频繁执行独占控制,系统性能可能会下降,因为这会长时间占用总线。因此,建议尽可能使用 LDL/STC 指令执行独占控制。
  • 2 当使用 CAXI 指令执行互斥时,为防止上述注意事项 1 中描述的总线占用过多的问题,在锁获取失败后再次尝试获取锁之前执行 SNOOZE 指令,并调整锁获取循环执行间隔。

示例代码
以下显示了使用 CAXI 指令执行的自旋锁示例代码。

锁获取

1
2
3
4
5
6
7
8
9
 MOV lock_adr, r20
Lock:
MOV 1, r21
CAXI [r20], r0, r21
BZ Lock_success
SNOOZE
BR Lock
Lock_success:

所释放:

1
ST.W r0, 0[r20]