Renesas-RH850 CPU System - CPU - Hazard Control
Renesas学习笔记
CPU System : CPU - Hazard Control
危险控制
为确保后续指令中准确引用内存和系统寄存器的操作结果,此 CPU 可能需要在软件中进行危险管理。
- 专用于同步处理的特殊指令
- 存储指令的执行完成保证
- 更新系统寄存器后的危险控制
1 同步处理
为了提高处理性能,只要前后指令之间没有依赖关系,此 CPU 在执行后续指令时不会等待前面指令处理完成。例如,当存储指令要更新操作速度比 CPU 慢的外设的控制寄存器值时,即使寄存器的更新未完成,而总线系统仍在处理存储值的操作,后续指令的执行也会继续。因此,如果后续指令必须通过软件等待前面指令的处理完成,则需要同步处理步骤。
此外,当单个 CPU 执行多个加载和存储指令时,执行结果保证按程序指令的顺序。然而,为了保证多个总线主控设备之间的数据访问顺序(在互斥控制部分之外),应在后续数据访问前进行同步处理。有关同步处理的详细信息,请参见第 3.9.1 节,存储指令完成和后续指令生成的同步和第 3.9.2 节,加载指令完成和后续指令生成的同步。
此 CPU 提供了四种专用于同步处理的指令。此外,由于等待前面的加载处理结果依赖于通用寄存器并由硬件自动处理,因此不需要软件进行同步处理。
1.1 SYNCP
SYNCP 指令是一种用于流水线同步处理的特殊指令,使流水线在开始执行后续指令之前等待前面指令执行结果的反映。尽管 SYNCP 指令会等待所有前面加载处理(直到将加载的值存储到通用寄存器)结果的完成,但不会等待存储处理(存储目标内存位置和内存映射控制寄存器的更新)的结果。有关如何确保存储处理结果反映在后续指令中的信息,请参见第 3.2.7.2 节,存储指令完成的保证。
1.2 SYNCM
SYNCM 指令是一种用于内存访问同步处理的特殊指令,等待所有前面加载处理(直到将加载的值存储到通用寄存器)结果的完成和所有前面存储处理(存储目标内存位置和内存映射控制寄存器的更新)结果的完成。然而,对于那些存储被推测性完成的总线系统和外设(导致写入内存和控制寄存器的完成延迟),SYNCM 指令不保证存储指令执行的完成。有关如何确保在这种情况下存储处理结果反映在后续指令中的信息,请参见第 3.2.7.2 节,存储指令完成的保证。
1.3 SYNCI
SYNCI 指令是一种用于指令提取同步的特殊指令。它使已经被提取到流水线但未执行的后续指令被丢弃,并从最早被丢弃的指令重新开始提取。当必须在随后提取的指令处理中反映前面指令的结果时,使用此指令。尽管 SYNCI 指令会等待所有前面加载处理(直到将加载的值存储到通用寄存器)结果的完成,但不会等待存储处理(存储目标内存位置和内存映射控制寄存器的更新)的结果。如果已发出了缓存指令,此指令还会等待指令缓存操作的完成。
如果需要在后续指令提取中反映存储指令执行的结果,例如更改自修改代码或在代码闪存区域之间切换,则应在 SYNCI 指令前执行虚拟读取。这样可以等待存储指令执行的结果,从而在后续指令提取中反映这些结果。有关详细信息,请参见第 3.2.7.2 节,存储指令完成的保证。
1.4 SYNCE
此 CPU 的 SYNCE 指令不执行与同步相关的处理。
2 保证存储指令的完成
在相同地址下,存储指令的完成可能比加载指令看起来更快。然而,当指令完成时,存储的数据可能实际上还没有被存储。例如,在多核同步或外设操作中,只有在确认数据已经存储到目标位置后,才应进行与存储值相关的处理。应该在存储指令执行后通过软件检查这一点。
此 CPU 提供了两种等待存储进展的方式。
2.1 使用 SYNCM 指令等待存储的完成
执行 SYNCM 指令会使操作等待,直到前面的存储指令的结果会被后续读取正确读取。这确保了在存储在内存中的指令要执行或数据要通过内存传输到其他 CPU 核心或通过 DMA 传输时的确认执行。
在以下示例中,两条存储指令的执行后,继续执行其他“操作”前,需要执行 SYNCM 指令等待存储完成。这里,分支到存储指令代码的地址、通知其他 CPU 等处理属于“操作”类别。
1 | ST.W r21, 0[r1] // 存储数据1 |
然而,SYNCM 指令不保证前面的存储指令的结果已经反映在目标位置。例如,当将值存储在外设的寄存器中时,在等待由于 SYNCM 指令而结束时,外设的寄存器可能尚未更新,结果可能不是预期的。在这种情况下,使用虚拟读取来等待。这在第 3.2.7.2 (2) 节中描述,使用虚拟读取等待存储的完成。
此外,由于 SYNCM 指令要求硬件操作等待响应其执行,因此仅在 CPU 能识别存储进展的总线从设备上有效。如果一个总线从设备能够仲裁来自多个总线主控设备的请求,或者通过总线桥连接到总线,CPU 无法识别存储进展,因此使用 SYNCM 指令来引起等待可能无效。
支持使用 SYNCM 指令等待此 CPU 中存储完成的总线从设备(地址组)列于表 3.136 中。
总线从设备 | 描述 |
---|---|
L1RAM(给定 CPU) | 等待内存更新也是可能的。*1 |
L1RAM(其他 CPU) | 可以假设此设备有两个 CPU 核心的配置。对于具有三个或更多核心的配置,请参见第 3.9.1.3 节,SYNCM 的产品信息。 |
L2RAM | 可以假设此设备有两个共享 L2RAM 的 CPU 核心的配置。对于具有三个或更多核心或多个 L2RAM 的配置,请参见第 3.9.1.3 节,SYNCM 的产品信息。 |
INTC1 | 这是用于与 CPU 连接的专用中断控制器。 |
其他 | 取决于连接的总线或从设备的规格。详细信息请参见第 3.9.1.3 节,SYNCM 的产品信息。 |
注意 *1: 详细信息请参见第 3.2.7.2 (2) 节,使用虚拟读取等待存储完成。
SYNCM 指令导致等待的指令是所有前面的存储和加载指令。同时运行多个存储和加载指令会增加等待时间长于必要的可能性。
不需要每条存储指令都执行一个 SYNCM 指令。在特定总线从设备中按内存类型、外设等单元连续存储后,在最后一个存储指令之后执行一个 SYNCM 指令会导致等待所有前面的存储指令完成。在上述示例中,两条存储指令执行后执行一个 SYNCM 指令。
2.2 使用虚拟读取等待存储完成
在存储指令之后立即执行相同地址的加载指令也可用于等待存储指令的完成。这种方法不同于使用 SYNCM 指令引起等待,因为它涉及实际等待存储指令的结果得到反映。另一方面,这种方法可能需要比使用 SYNCM 指令更多的周期。
将 r0 指定为虚拟读取加载值的存储目标,允许在不需要这些加载值时丢弃它们,而不会破坏其他寄存器值。以下是一个代码示例。
1 | ST.W r21, 0[r1] // 存储数据1 |
不同于使用 SYNCM 指令,这种方法结合了 CPU 的功能来引起等待。由于它不需要专用硬件,因此可以与许多总线从设备一起使用。
另一方面,如果在到目标的路径中存在临时存储数据的缓存,即使存储值尚未到达其目标,后续加载指令也会读取该值,因此在这种情况下,此方法不能保证存储指令的完成。此外,根据外围设备的规格,在通过存储指令更改设置后可能需要经过一段预定时间才能读取所需值。除了这种方法之外,此类情况还需要等待预定时间的处理。
尽管此 CPU 不包括此类缓存功能或在读取前需要经过一段时间的外围功能,但情况取决于产品。有关详细信息,请参见第 3.9.1.4 节,等待存储完成的产品信息。
与使用 SYNCM 指令一样,在使用虚拟读取时,连续在特定总线从设备中存储后,仅在最后一个存储指令之后的单个加载指令在等待所有前面的存储指令完成时有效。
表 3.137 列出了使用虚拟读取等待时有效的总线从设备。
总线从设备 | 描述 |
---|---|
L1RAM(其他 CPU) | 等待内存更新也是可能的。*1 |
L2RAM | 可以假设此设备有两个 CPU 核心共享的配置。有关详细信息,请参见第 3.9.1.4 节,等待存储完成的产品信息。 |
INTC1 | 这是用于与 CPU 连接的专用中断控制器。 |
其他 | 取决于连接的总线或从设备的规格。详细信息请参见第 3.9.1.4 节,等待存储完成的产品信息。 |
在访问给定 CPU 的 L1RAM 时,为了提高处理效率,加载指令的执行可能在内存实际更新之前完成。另一方面,可以执行 SYNCM 指令以等待内存更新的完成。因此,使用 SYNCM 指令等待给定 CPU 的 L1RAM 中存储指令的完成。
当需要在后续指令提取中反映存储指令执行的结果时,例如由于更改自修改代码或在代码闪存区域之间切换,应在虚拟读取后执行 SYNCI 指令而不是 SYNCP 指令。这会导致等待存储指令执行的结果,从而在后续指令提取中反映这些结果。以下是一个代码示例。
1 | ST.W r21, 0[r1] // 与指令提取相关的更改 |
3 系统寄存器更新后的危险管理
如果执行 LDSR 指令以更新系统寄存器的设置,然后再执行 STSR 指令读取该系统寄存器或执行使用该系统寄存器的 CALLT 指令等,则必须反映新设置以执行所需的操作。
此 CPU 保证,如果使用 LDSR 指令更新表 3.138 中列出的系统寄存器,新寄存器设置将在执行后续指令时应用。然而,它不保证新设置会应用于指令提取。在这种情况下,需要同步过程。此外,EI 或 DI 指令的执行与通过 LDSR 指令更新 PSW 的情况相同;即,保证 EI 或 DI 指令更新的值应用于后续指令。
如果更新与指令提取相关的设置或表 3.138 中未列出的系统寄存器,通过在 LDSR 指令后立即执行任何以下同步过程,可以反映新寄存器设置。应根据新寄存器设置和后续操作的详细信息确定适当的同步过程。
有关用于同步过程的 SYNCI 或 SYNCP 指令,请参见第 3.2.7.1 节,同步处理。
3.1 更新与指令提取相关的设置
为了有效地将从内存读取的指令代码提供给指令执行单元,指令提取的操作独立于指令执行单元,并且是推测性的。这意味着在系统寄存器更新完成后,不知道随后指令代码的读取进度。换句话说,不知道指令提取应用于系统寄存器新设置的结果。因此,对于与指令提取相关的系统寄存器更新,需要明确的同步过程。此过程对于表 3.138 中列出的系统寄存器的更新也是必要的,以确保更新在指令提取中反映。
与指令提取相关的系统寄存器如下所列:
- CPU 操作模式:PSW.UM、PSW.CU1、PSW.CU0
- 访问保护:SPID
- 内存保护:MPU 功能寄存器
- 指令缓存:缓存操作功能寄存器
- 指令提取:指令提取控制寄存器
如果更新了上述系统寄存器的设置,通过执行 SYNCI、EIRET 或 FERET 指令,当提取后续指令时,新设置将得到确保反映。这里,这些指令称为“指令提取同步指令”。有关 EIRET 和 FERET 指令的使用,请参见第 3.2.7.3 (7) 节,同步过程中 EIRET 和 FERET 指令的使用。
对于提取指令提取同步指令本身,是否反映了系统寄存器的更新尚不确定。在这些情况下,必须注意以下事项。
(a) 更新 PSW.UM
当使用 LDSR 指令更新 PSW,特别是设置 PSW.UM(为 1)时,这会启用内存保护功能,确保用于同步指令提取的 SYNCI 指令的提取不会导致内存保护违规。此外,设置 PSW.UM 会禁用某些指令的执行和某些系统寄存器的更新。
另一方面,当执行 EIRET 或 FERET 指令时,EIPSW 或 FEPSW 中的值被传输到 PSW 作为指令的操作。这意味着指令提取发生在指令本身更新 PSW.UM 之前。因此,建议通过 EIRET 或 FERET 指令更新 PSW.UM。
(b) 更新 PSW.CU1 和 PSW.CU0
在更新 PSW.CU1 或 PSW.CU0 之后,如果在没有同步过程的情况下执行 FXU 或 FPU 指令,可能无法正确检测到协处理器不可用异常 (UCPOP)。为避免这种情况,请在更新这些位后执行 SYNCI 指令进行同步。与更新 PSW.UM 不同,通过 SYNCI 指令可以确保 PSW.CU1 或 PSW.CU0 的更新和协处理器不可用异常的检测同步。
对于同时更新 PSW.CU1 或 PSW.CU0 和 PSW.UM,建议使用第 3.2.7.3 (1)(a) 节中描述的 EIRET 或 FERET 指令更新 PSW.UM。
(c) 更新 SPID
SPID 由内存保护功能和 CPU 之外的总线系统引用。如果将没有访问内存资源或外围设备权限的 ID 设置为 SPID,则指令提取不会正确进行。确保将适当的 ID 设置为 SPID。为了确保总线系统引用 SPID 的任何更新,可能需要一次禁用指令缓存。有关详细信息,请参见第 44 节,功能安全。
(d) 更新 MPU 功能寄存器
通过操作 MPU 功能寄存器更新内存保护设置的详细信息,请参见第 3.2.7.3 (2) 节,更新 MPU 的内存保护设置。
为了在提取后续指令时反映更新的设置,执行 SYNCI、EIRET 或 FERET 指令。然而,尚不清楚指令提取同步指令本身是否使用新保护设置提取。在这种情况下,需要进行以下操作。
- 仅在用户模式下启用内存保护,并在监督模式下更新设置。
- 在允许执行指令的区域更新内存保护设置。
- 确保为包含指令提取同步指令的内存区域启用指令执行。
对于使用上述操作 1 更新 PSW.UM,建议使用第 3.2.7.3 (1)(a) 节中描述的 EIRET 或 FERET 指令更新 PSW.UM。
(e) 更新缓存操作功能寄存器
通过指令更新这些寄存器不需要特定的同步过程。然而,如果要确保指令缓存的禁用状态反映在提取后续指令中,请在更新缓存操作功能寄存器后执行指令提取同步指令。
(f) 更新指令提取控制寄存器
通过指令更新这些寄存器不需要特定的同步过程。
3.2 更新 MPU 的内存保护设置
表 3.138 中显示的 MPU 系统寄存器保证其最新设置在后续指令中得到反映,但这不适用于配置保护区域设置的其他系统寄存器(MPIDX、MPLA、MPUA、MPAT 和 MPIDn (n = 0 到 7))。
为了通过使用后续 STSR 指令读取由 LDSR 指令更新的设置,需要第 3.2.7.3 (4) 节中描述的同步过程,更新寄存器bank功能相关系统寄存器。
有关在指令提取中反映更新的内存保护设置,请参见第 3.2.7.3 (1) 节,更新与指令提取相关的设置。
要在使操作数访问的指令中反映更新的内存保护设置,请在更新后执行 SYNCI 或 SYNCP 指令。这确保新保护设置在后续指令的操作数访问中得到反映。
EIRET 和 FERET 指令可以代替 SYNCI 和 SYNCP 指令使用。特别是对于更新与指令提取相关的内存保护设置以及进行操作数访问的情况,建议使用 EIRET 或 FERET 指令。
3.3 更新与中断相关的系统寄存器
如表 3.138 所示,当更新与中断相关的系统寄存器(ISPR、INTCFG、PLMR)时,保证在执行后续指令时反映这些更新。
然而,例如,当更新 INTCFG 的设置以停止自动更新 ISPR 时,如果在 INTCFG 更新后和执行更新 ISPR 的 LDSR 指令之前生成中断,仅在中断处理中反映 INTCFG 的更新。由于未反映 ISPR 的更新,因此无法执行所需的中断处理。
为避免这种情况,建议在更新与中断相关的系统寄存器时,通过将 PSW.ID 设置为 1 来禁用中断。
还建议在禁用中断时更新指定中断处理程序向量地址的 PSW.EBV 和 EBASE。有关详细信息,请参见第 3.2.7.3 (8) 节,更新 PSW.EBV 和 EBASE。
3.4 更新寄存器bank功能相关的系统寄存器
如表 3.138 所示,当更新与寄存器bank功能相关的系统寄存器(RBCR0、RBCR1、RBNR、RBIP)时,保证在执行后续指令时反映这些更新。例如,如果在执行更新 RBIP 的 LDSR 指令后生成中断,使用更新的 RBIP 值执行自动上下文保存到寄存器银行。
然而,例如,当更新 RBCR0 和 RBCR1 的设置时,如果在更新 RBCR0 后和执行更新 RBCR1 的 LDSR 指令之前生成中断,仅在自动上下文保存到寄存器银行中反映 RBCR0 的更新。由于未反映 RBCR1 的更新,因此无法执行所需的处理。
为避免这种情况,建议在更新与寄存器银行功能相关的系统寄存器时,通过将 PSW.ID 设置为 1 来禁用中断。
对于仅 RBCR0,通过 SYNCI 指令的同步过程需要确保将新寄存器设置反映到后续的 RESBANK 指令中。以下是一个代码示例。
1 | DI // 禁用中断 |
3.5 使用 STSR 指令读取系统寄存器
在执行 LDSR 指令更新系统寄存器后,在执行 STSR 指令进行读取操作之前执行 SYNCP 指令。由于 SYNCP 指令会等待直到完成前面的 LDSR 指令的执行,因此确保读取新寄存器设置。
对于表 3.138 中显示的系统寄存器,通过 SYNCP 指令无需同步过程即可读取新寄存器设置。
3.6 由后续指令引用系统寄存器
在执行 LDSR 指令更新系统寄存器后,在执行引用系统寄存器的指令之前执行 SYNCP 指令。由于 SYNCP 指令会等待直到完成前面的 LDSR 指令的执行,因此确保新寄存器设置得到反映。
3.7 在同步过程中使用 EIRET 和 FERET 指令
EIRET 和 FERET 指令被定义为从其对应异常级别的异常处理程序返回的指令。这些指令可以同时设置任何 PC 和 PSW,因此可以用作此 CPU 中的同步过程指令。
要使用 EIRET 指令进行同步过程,设置适当的值到 EIPC 和 EIPSW 并执行指令。要使用 FERET 指令进行同步过程,设置适当的值到 FEPC 和 FEPSW 并执行指令。
设置 EIPC 和 FEPC 的值作为这些指令执行后的 PC。设置 EIPSW 和 FEPSW 的值作为这些指令执行后的 PSW。
请注意,这些指令是监督特权指令。这意味着,PSW.UM 的状态只能从 0(清除)更改为 1(设置),从监督模式更改为用户模式。
有关 EIRET 和 FERET 指令的详细信息,请参见《RH850G4MH 用户手册:软件》。
3.8 更新 PSW.EBV 和 EBASE
EBASE 是一个指示异常处理程序向量地址的寄存器。当 PSW.EBV 设置为 1 时启用。建议的更新过程如下。
- 将 PSW.ID 设置为 1
- 清除 PSW.EBV 为 0(同时更新 PSW.ID 是可能的)
- 更新 EBASE
- 将 PSW.EBV 设置为 1
- 清除 PSW.ID 为 0(同时更新 PSW.EBV 是可能的)
对于以上过程中的 PSW.UM 更新,建议使用第 3.2.7.3 (1)(a) 节中描述的 EIRET 或 FERET 指令更新 PSW.UM。