ARM会定期发布该架构的新版本。它们会添加新功能或对现有行为进行更改。此类更改几乎总是向后兼容的,这意味着在旧版本的体系结构上运行的用户代码将继续在新版本上正确运行。当然,为了利用新特性而编写的代码无法在缺乏这些特性的旧处理器上运行。在体系结构的所有版本中,一些系统特性和行为都是由实现定义的。例如,体系结构没有定义各个指令的缓存大小或循环时间。这些是由个别的核心和SoC决定的。每个架构版本还可以定义可选的扩展。这些可能在处理器的特定实现中实现。例如,在ARMv7体系结构中,高级SIMD (Advanced SIMD, NEON)技术是可选的扩展,在第7章介绍NEON时会介绍它。ARMv7体系结构也有配置文件的概念。这些是描述针对不同市场和用途的处理器的体系结构的变体。
ArmV7有三个体系分别是ArmV7-A,ArmV7-R,ArmV7-M
A 应用程序配置文件定义了一种针对高性能处理器的体系结构,支持使用内存管理单元(MMU)的虚拟内存系统,因此能够运行功能齐全的操作系统。提供了对ARM和Thumb指令集的支持。ARMv8-A架构支持AArch32状态,这是该架构的32位实现,向后兼容ARMv7-A。
R 实时概要文件定义了针对需要的系统的体系结构确定性定时和低中断延迟。不支持虚拟内存系统,但可以使用简单内存来保护内存区域保护单元(MPU)。R系列一般用于对实时性要求较高的场景。
M 微控制器配置文件定义了一种针对低成本系统的体系结构,其中低延迟的中断处理至关重要。它使用了与其他配置文件不同的异常处理模型,并且只支持Thumb指令集的一个变体。M系列一般用于控制以及低功耗方面。
从80年代中期的第一个测试硅到90年代早期的第一个ARM6和ARM7器件,ARM架构变化相对较小。在该体系结构的第一个版本中,大部分的加载、存储和算术操作以及异常模型和寄存器集都由ARM1实现。版本2增加了multiply和multiply-accumulate指令,并支持协处理器,还有其他一些创新。这些早期的处理器只支持26位的地址空间。该体系结构的版本3分离了程序计数器和程序状态寄存器,并添加了几个新模式,支持32位地址空间。版本4增加了对半字加载和存储操作的支持,以及一个额外的内核级特权模式。如果不熟悉ARM体系结构的读者在本描述中使用了他们不熟悉的术语,也不用担心,因为所有这些主题都将在后续章节中介绍。ARMv4T架构引入了Thumb(16位)指令集,由ARM7TDMI®和ARM9TDMI®处理器实现,这些产品已经出货数十亿美元。ARMv5TE架构增加了对dsp类型操作和饱和运算以及ARM/Thumb互操作的改进。ARMv6做了许多增强,包括支持非对齐内存访问、对内存架构的重大更改和多核支持,以及支持在32位寄存器中操作字节或半字的SIMD操作。它还提供了许多可选的扩展,特别是Thumb-2和安全扩展(TrustZone)。Thumb-2将Thumb扩展为混合长度(16位和32位)指令集。
ARMv7-A体系结构强制使用Thumb-2扩展,并添加了Advanced SIMD扩展(NEON)
多年来,ARM对处理器采用了顺序编号系统,从ARM9到ARM8,再到ARM7。各种数字和字母被附加到基族中以表示不同的变体。例如,ARM7TDMI处理器有T表示Thumb, D表示Debug, M表示快速乘法器,I表示EmbeddedICE。
对于ARMv7架构,ARM有限公司为其处理器采用了Cortex品牌名称,并附带一个字母表示处理器支持三种配置文件(A, R或M)中的哪一种。
下图显示了不同版本的架构如何对应不同的处理器实现。这个图并不全面,也不包括所有的体系结构版本或处理器实现。
我们常见的STM32F1,F4系列就是ARMV7-M架构的,可以去官网下载对应的我文档,这里介绍ArmV7-A。
ARM Cortex-A7处理器是ARM开发的最节能的应用处理器,扩展了ARM在入门级智能手机、平板电脑和其他先进移动设备上的低功耗领导地位。下图时ARMV7-Ac处理器架构框图
上图可以看出
ARM架构是一种模态架构。在引入安全扩展之前,它有7种处理器模式,如下表图所示。有6种特权模式和1种非特权用户模式。特权是执行某些在用户(非特权)模式下无法完成的任务的能力。在用户态下,对影响系统整体配置的操作有限制,例如MMU配置和缓存操作。ARMV7-M如我们的STM32只由特权和非特权两种。
在不同处理器模式下对LR(R14)寄存器的调整。
特定处理器模式和状态的存在取决于处理器是否实现了相关的架构扩展,如下图所示。
当前处理器模式和执行状态包含在当前程序状态寄存器(current Program Status Register, CPSR)中。改变处理器状态和模式可以通过特权软件显式地进行,也可以通过异常处理来实现。
ARM架构提供了16个32位通用寄存器(r0 ~ r15)供软件使用。其中15个(r0 ~ r14)可用于通用数据存储,R15为程序计数器,其值随着核心执行指令的变化而变化。软件对R15的显式写入将改变程序流程。软件也可以访问CPSR,以及先前执行模式下保存的CPSR副本,称为保存的程序状态寄存器(SPSR)。
Cortex-A7 有 9 种运行模式,每一种运行模式都有一组与之对应的寄存器组。每一种模式可见的寄存器包括 15 个通用寄存器(R0~R14)、一两个程序状态寄存器和一个程序计数器 PC。在这些寄存器中,有些是所有模式所共用的同一个物理寄存器,有一些是各模式自己所独立拥有的,各个模式所拥有的寄存器如下图所示。
浅色字体的是与 User 模式所共有的寄存器,蓝绿色背景的是各个模式所独有的寄存器。可以看出,在所有的模式中,低寄存器组(R0~R7)是共享同一组物理寄存器的,只是一些高寄存器组在不同的模式有自己独有的寄存器,比如 FIQ 模式下 R8~R14 是独立的物理寄存器。假如某个程序在 FIQ 模式下访问 R13 寄存器,那它实际访问的是寄存器 R13_fiq,如果程序处于 SVC 模式下访问 R13 寄存器,那它实际访问的是寄存器 R13_svc。总结一下,CortexA 内核寄存器组成如下:
34 个通用寄存器,包括 R15 程序计数器(PC),这些寄存器都是 32 位的。
8 个状态寄存器,包括 CPSR 和 SPSR。
Hyp 模式下独有一个 ELR_Hyp 寄存器。
R0~R15 就是通用寄存器,通用寄存器可以分为以下三类:
未备份寄存器,即 R0~R7。
备份寄存器,即 R8~R14。
程序计数器 PC,即 R15。
分别来看一下这三类寄存器:
未备份寄存器
未备份寄存器指的是 R0~R7 这 8 个寄存器,因为在所有的处理器模式下这 8 个寄存器都是同一个物理寄存器,在不同的模式下,这 8 个寄存器中的数据就会被破坏。所以这 8 个寄存器并没有被用作特殊用途。
备份寄存器
备份寄存器中的 R8~R12 这 5 个寄存器有两种物理寄存器,在快速中断模式下(FIQ)它们对应着 Rx_irq(x=8~12)物理寄存器,其他模式下对应着 Rx(8~12)物理寄存器。FIQ 是快速中断模式,看名字就是知道这个中断模式要求快速执行! FIQ 模式下中断处理程序可以使用 R8~R12寄存器,因为 FIQ 模式下的 R8~R12 是独立的,因此中断处理程序可以不用执行保存和恢复中断现场的指令,从而加速中断的执行过程。备份寄存器 R13 一共有 8 个物理寄存器,其中一个是用户模式(User)和系统模式(Sys)共用的,剩下的 7 个分别对应 7 种不同的模式。R13 也叫做 SP,用来做为栈指针。基本上每种模式都有一个自己的 R13 物理寄存器,应用程序会初始化 R13,使其指向该模式专用的栈地址,这就是常说的初始化 SP 指针。备份寄存器 R14 一共有 7 个物理寄存器,其中一个是用户模式(User)、系统模式(Sys)和超级监视模式(Hyp)所共有的,剩下的 6 个分别对应 6 种不同的模式。
R14(链接寄存器LR)保存了在使用Link (BL)指令时输入的子例程的返回地址。当它不支持从子例程返回时,它也可以用作通用寄存器。R14_svc、R14_irq、R14_fiq、R14_abt和R14_und类似地用于在中断和异常发生时,或在中断或异常例程中执行分支和链接指令时,保存R15(PC)的返回值。
程序计数器 R15 也叫做 PC,R15 保存着当前执行的指令地址值加 8 个字节,这是因为 ARM的流水线机制导致的。ARM 处理器 3 级流水线:取指->译码->执行,这三级流水线循环执行,比如当前正在执行第一条指令的同时也对第二条指令进行译码,第三条指令也同时被取出存放在 R15(PC)中。我们喜欢以当前正在执行的指令作为参考点,也就是以第一条指令为参考点,那么 R15(PC)中存放的就是第三条指令,换句话说就是 R15(PC)总是指向当前正在执行的指令地址再加上 2 条指令的地址。对于 32 位的 ARM 处理器,每条指令是 4 个字节,所以:R15 (PC)值 = 当前执行的程序位置 + 8 个字节。
所有的处理器模式都共用一个 CPSR 物理寄存器,因此 CPSR 可以在任何模式下被访问。CPSR 是当前程序状态寄存器,该寄存器包含了条件标志位、中断禁止位、当前处理器模式标志等一些状态位以及一些控制位。所有的处理器模式都共用一个 CPSR 必然会导致冲突,为此,除了 User 和 Sys 这两个模式以外,其他 7 个模式每个都配备了一个专用的物理状态寄存器,叫做 SPSR(备份程序状态寄存器),当特定的异常中断发生时,SPSR 寄存器用来保存当前程序状态寄存器(CPSR)的值,当异常退出以后可以用 SPSR 中保存的值来恢复 CPSR。因为 User 和 Sys 这两个模式不是异常模式,所以并没有配备 SPSR,因此不能在 User 和Sys 模式下访问 SPSR,会导致不可预知的结果。由于 SPSR 是 CPSR 的备份,因此 SPSR 和CPSR 的寄存器结构相同。
N(bit31):当两个补码表示的有符号整数运算(CMP指令)的时候,N=1 表示运算对的结果为负数,N=0
表示结果为正数。
**Z(bit30):**Z=1 表示运算结果为零,Z=0 表示运算结果不为零,对于 CMP 指令,Z=1 表示进行比较的两个数大小相等。
C(bit29):在加法(ADD)指令中,当结果产生了进位,则 C=1,表示无符号数运算发生上溢,其它情况下 C=0。在减法指令中,当运算中发生借位,则 C=0,表示无符号数运算发生下溢,其它情况下 C=1。对于包含移位操作的非加/减法运算指令,C 中包含最后一次溢出的位的数值,对于其它非加/减运算指令,C 位的值通常不受影响。
V(bit28):对于加/减法运算指令,当操作数和运算结果表示为二进制的补码表示的带符号数时,V=1 表示符号位溢出,通常其他位不影响 V 位。
**Q(bit27)**仅 ARM v5TE_J 架构支持,表示饱和状态,Q=1 表示累积饱和,Q=0 表示累积
不饱和。
**IT:(bit26:25)**和 IT(bit15:bit10)一起组成 IT[7:0],作为 IF-THEN 指令执行状态。
**J(bit24):**仅 ARM_v5TE-J 架构支持,J=1 表示处于 Jazelle 状态,此位通常和 T(bit5)位一起表示当前所使用的指令集:
J | T | 描述 |
---|---|---|
0 | 0 | ARM |
0 | 1 | Thumb |
1 | 1 | ThumbEE |
1 | 0 | Jazelle |
GE(bit19:16):SIMD 指令有效,大于或等于。
**IT(bit15:10):**参考 IT[1:0]。
**E(bit9):**大小端控制位,E=1 表示大端模式,E=0 表示小端模式。
**A(bit8):**禁止异步中断位,A=1 表示禁止异步中断。
**I(bit7):**I=1 禁止 IRQ,I=0 使能 IRQ。
**F(bit6):**F=1 禁止 FIQ,F=0 使能 FIQ。
**T(bit5):**控制指令执行状态,表明本指令是 ARM 指令还是 Thumb 指令,通常和 J(bit24)一起表明指令类型,参考 J(bit24)位。
CP15作为系统控制协处理器,提供了控制核心的许多功能。它可以包含多达16个32位主寄存器。对CP15的访问是权限控制的,并非所有寄存器都在用户态可用。CP15寄存器访问指令指定所需的主寄存器,指令中的其他字段用于更精确地定义访问,并增加CP15中物理32位寄存器的数量。CP15的16个主寄存器被命名为c0到c15,但经常被称为名称。例如,CP15系统控制寄存器称为CP15.(CTLR)。
SCTLR是使用CP15访问的众多寄存器中的一个,用于控制标准内存、系统设施,并为在核心中实现的函数提供状态信息,结构如下图所示
所有的ARM内核都有两个外部中断请求,即FIQ和IRQ。这两种都是电平敏感的低活跃输入。各个实现都有中断控制器,可
以接受来自各种外部源的中断请求,并将其映射到FIQ或IRQ上,从而导致内核发生异常。一般来说,只有明确了适当的
CPSR禁用位(F位和I位),并且断言了相应的输入,才能发生中断异常。CPS指令提供了一种简单的机制来启用或禁用由
CPSR a、I和F位(分别是异步夭折、IRQ和FIQ)控制的异常。CPS IE和CPS ID分别启用和禁用异常。使用字母A、I和f中的
一个或多个指定要启用或禁用的异常。省略相应的字母的异常将不会被修改。在Cortex-A系列处理器中,可以通过配置内
核使fiq无法被软件屏蔽。这被称为不可屏蔽FIQ,由硬件配置输入信号控制,该信号在核心重置时进行采样。当遇到FIQ异
常时,它们仍然会被自动屏蔽。
在big-endian机器上,对象在内存中的最高有效字节存储在最低有效地址(接近于0)上。在小端序的计算机上,最高有效字节存储 在最高地址。
int i = 0x44332211;
unsigned char c = *(unsigned char *)&i;
在32位大端序机器上,c表示i的最高位字节的值:0x44。在小端序的机器上,c是i的最低有效字节:0x11。
在ARM内核上,访问的对齐非常重要。在老式的ARM处理器上, 可以访问未对齐的地址,但行为与使用ARMv7体系结构
的地址不同。在ARM7和ARM9处理器上,非对齐LDR在内存系统中执行的方式与对齐访问相同,但返回的数据会被旋
转,因此请求地址处的数据会被放置在加载寄存器的最低有效字节中。一些老的编译器和操作系统能够使用这种行为进行
巧妙的优化。在将代码从ARMv4或ARMv5移动到ARMv7架构时,这可能表示可移植性问题。ARM mmu可以配置为自动
检测这种非对齐访问并中止它们(使用CP15:SCTL位)。
与对齐访问相比,这些非对齐访问可能需要额外的周期,因此对齐也是一个性能问题。此外,这种访问不能保证是原子性的。这意味着外部代理(系统中的另一个核心)可能执行内存访问,该访问似乎是通过非对齐访问的一部分发生的。例如,它可能读取访问的位置,并看到某些字节的新值和其他字节的旧值,下图为对齐访问。
按字对齐的地址是4的倍数,例如0x100、0x104、0x108、0x10C、0x110。对齐访问的例子。
地址1处的一个未对齐字如上图所示。它从0处的单词中取出三个字节,从4处的单词中取出一个字节。
对齐效果对性能有显著影响的一个简单例子是memcpy()的使用。在字对齐的地址之间复制少量字节将被编译为LDM或STM指令。复制对齐到单词边界的较大内存块通常使用优化的库函数完成,该函数还将使用LDM或STM。复制开始或结束点不在单词边界上的内存块可能会导致对通用memcpy()函数的调用,这可能会明显变慢。尽管如此,如果源和目标同样没有对齐,那么只有起始片段和结束片段是非最优的。每当执行显式类型转换时,这种转换总是带有对齐含义。
FI – FIQ 配置使能
V 这个位选择异常向量表的基址。
第一列给出了异常在向量表中的偏移量。这是一个指令表,当出现异常时,ARM内核跳转到这个指令表。这些指令位于内存中的特定位置。向量的默认基址是0x00000000,但大多数ARM内核允许将向量的基址移动到0xFFFF0000(或HIVECS)。所有的Cortex-A系列处理器都允许这样做,这是Linux内核选择的默认地址。实现安全扩展的内核还可以使用CP15向量基地址寄存器,为安全状态和非安全状态分别设置向量基地址。
主要用于对cache的控制启用,操作方法如下。
官方SDK中汇编启动文件中的示例
/* Reset SCTlr Settings */
mrc p15, 0, r0, c1, c0, 0 /* Read CP15 System Control register */
bic r0, r0, #(0x1 << 12) /* Clear I bit 12 to disable I Cache */
bic r0, r0, #(0x1 << 2) /* Clear C bit 2 to disable D Cache */
bic r0, r0, #0x2 /* Clear A bit 1 to disable strict alignment */
bic r0, r0, #(0x1 << 11) /* Clear Z bit 11 to disable branch prediction */
bic r0, r0, #0x1 /* Clear M bit 0 to disable MMU */
mcr p15, 0, r0, c1, c0, 0 /* Write value back to CP15 System Control register */
手册上的例子
MRC p15, 0, r0, c1, c0, 0 ; Read System Control Register configuration data
ORR r0, r0, #(1 << 2) ; Set C bit
ORR r0, r0, #(1 << 12) ; Set I bit
ORR r0, r0, #(1 << 11) ; Set Z bit 设置Z位具体干嘛的不清楚。
MCR p15, 0, r0, c1, c0, 0 ; Write System Control Register configuration data
清理缓存或缓存行意味着将脏缓存行的内容写入主内存,并清除缓存行中的脏位。这使得缓存行的内容和主内存的内容是一致的。这只适用于使用回写策略的数据缓存。缓存无效,且缓存清理操作可以通过缓存集、缓存方式或虚拟地址来执行。
在启用MMU之前,必须将转换表写入内存。TTBR寄存器必须设置为指向表。接下来可以使用下列代码序列来启用MMU:
MRC p15, 0, R1, c1, C0, 0 ;Read control register
ORR R1, #0x1 ;Set M bit
MCR p15, 0,R1,C1, C0,0 ;Write control register and enable MMU
如果启用MMU(内存管理单元)改变了代码当前执行区域的地址映射,则必须小心。
ARMv7体系结构是一个32位处理器体系结构。它也是一种加载/存储体系结构,这意味着数据处理指令只对通用寄存器中的值进行操作。只有加载和存储指令才能访问内存。通用寄存器也是32位的。当我们提到一个字时,指的是32位。因此,双字是64位宽,半字是16位宽。尽管ARMv7体系结构是32位体系结构,但单个处理器的实现并不一定对所有块和互连都使用32位宽度。例如,可以使用64位或更宽的路径来进行指令获取或数据访问。大多数ARM处理器支持两种甚至三种不同的指令集,而有些处理器(例如Cortex-M3处理器)实际上并不执行原始的ARM指令集。ARM处理器至少可以使用两种指令集。
ARM(32位指令)
这是最初的ARM指令集。
Thumb指令集
首先被添加到ARM7TDMI处理器中,并且只包含16位指令,这以牺牲一些性能为代价提供了更小的程序(内存占用在较小的嵌入式系统中可能是一个主要问题)。最近的处理器,包括那些在Cortex-A系列中的处理器,支持Thumb-2技术,它扩展了Thumb指令集,以提供16位和32位指令的混合。这样可以兼得两者的优点,性能与ARM指令集类似,代码大小与Thumb指令类似。由于Thumb-2的体积和性能优势,利用Thumb-2技术对所有代码进行编译或组装的情况越来越普遍。
cache这个词来源于法语动词cacher,意思是“隐藏”。这个词在处理器上的应用是显而易见的——缓存是处理器存储指令和数据的地方,对程序员和系统是隐藏的。在许多情况下,可以说缓存对您是透明的,或者对您是隐藏的。但我们将看到,很多时候,详细理解缓存的操作是很重要的。在ARM架构最初开发时,处理器的时钟速度和内存的访问速度大致相似。如今的处理器内核要复杂得多,运行速度也快了几个数量级。但是,外部总线和存储设备的频率还没有扩展到相同的程度。实现片上SRAM的小块是可能的,它们可以以与核心相同的速度运行,但与具有数千倍容量的标准DRAM块相比,这样的RAM非常昂贵。在许多基于ARM处理器的系统中,访问外部内存需要数十甚至数百个核心周期。
cache设计结构如下图所示。
本质上,缓存是位于核心和主内存之间的一个小的、快速的内存块(至少在概念上是这样)。它在主内存中保存数据项的副本。访问高速缓存的速度明显快于访问主内存的速度。因为高速缓存只保存了主内存内容的一个子集,它必须在主内存中同时存储数据项的地址和相关的数据。每当内核想要读写一个特定的地址时,它首先会在缓存中查找。如果它在缓存中找到了地址,它将使用缓存中的数据,而不必访问主内存。通过减少外部内存访问时间缓慢的影响,这显著提高了系统的潜在性能。通过避免驱动外部信号,它还降低了系统的功耗。缓存大小相对于系统中使用的整体内存较小。更大的缓存导致更昂贵的芯片。此外,增大内部核心缓存可能会限制核心的最大速度。高效地使用有限的资源是编写高效的应用程序以在核心上运行的关键部分。片上SRAM可以用来实现高速缓存,保存来自主内存的指令和数据的临时副本。代码和数据具有时间局部性和空间局部性。这意味着,随着时间的推移,程序倾向于重复使用相同的地址(时间局部性),并倾向于使用彼此邻近的地址(空间局部性)。例如,代码可以包含循环,这意味着可以重复执行相同的代码或多次调用一个函数。数据访问(例如对栈的访问)可以限制在较小的内存区域内。事实上,内核对内存的访问表现出局部性,而不是真正的随机,这使得缓存能够成功。写缓冲区是一个块,它将内核从外部内存总线执行存储指令时执行的写操作解耦。核心将与存储相关的地址、控制和数据值放入一组硬件缓冲区中。和缓存一样,它位于核心和主内存之间。这使得核心可以继续执行下一条指令,而不必停下来等待缓慢的主内存真正完成写操作。
看起来,缓存和写缓冲区自动带来了好处,因为它们加速了程序的执行。但它们也带来了一些在无缓存内核中不存在的问题。这样做的一个缺点是程序执行时间可能变得不确定。这意味着,由于缓存很小,只保存主内存的一个子集,它会在程序执行时迅速填满。在缓存满时,必须删除现有的代码或数据,为新项腾出空间。因此,在任何给定的时间,应用程序通常不可能确定是否在缓存中找到特定的指令或数据项。这意味着特定代码段的执行时间可能会有很大差异。在硬实时系统中,这可能是一个问题,因为硬实时系统需要强烈的确定性行为。此外,还需要一种方法来控制缓存和写缓冲区如何访问内存的不同部分。在某些情况下,我们希望核心从外部设备(如外设)读取最新的数据。例如,使用定时器外设的缓存值是不合理的。有时你希望core停下来等待store完成。所以缓存和写缓冲区给了你一些额外的工作。高速缓存和外部内存的内容有时可能不相同,这是因为处理器可能会更新高速缓存的内容,这些内容还没有写回主内存。或者,代理可以在核心获取自己的副本后更新主内存。这是一个一致性的问题。cache缺点主要是cache一致性问题。
在计算机科学中,内存层次指的是内存类型的层次结构,快而小的内存靠近核心,慢而大的内存远离核心。在大多数系统中,可以有辅助存储器,如磁盘驱动器和主存储器,如闪存、SRAM和DRAM。在嵌入式系统中,通常将其细分为片上内存和片外内存。与核心在同一芯片(或至少在同一包中)上的内存通常会快得多。缓存可以包含在层次结构的任何级别上,并可以在内存系统不同部分之间存在访问时间差异的情况下提高系统性能。在基于ARM处理器的系统中,一级(L1)缓存通常直接连接到获取指令、处理加载和存储指令的核心逻辑。这些是哈佛缓存,也就是说,指令和数据的缓存是分开的,它们实际上是核心的一部分。
多年来,由于SRAM的大小和速度的提高,L1缓存的大小有所增加。在写入时,16KB或32KB的缓存是最常见的,因为这是在1GHz或更高的核心速度下能够提供单周期访问的最大RAM大小。此外,许多ARM系统还具有二级(L2)缓存。这比L1缓存(通常为256KB、512KB或1MB)大,但速度较慢且统一(同时保存指令和数据)。它可以在核心内部,也可以实现为一个外部块,放置在核心和内存系统的其余部分之间。ARM L2C-310就是这种外部L2 cache控制器块的一个例子。此外,内核可以在集群中实现,每个内核都有自己的一级缓存。这样的系统需要一种机制来保持高速缓存之间的一致性,这样当一个核改变内存位置时,共享该内存的其他核都可以看到这个改变。
在冯·诺依曼体系结构中,指令和数据使用单一的缓存(统一的缓存)。改进的哈佛体系结构具有独立的指令总线和数据总线,因此有两个高速缓存,一个指令高速缓存(I-cache)和一个数据高速缓存(D-cache)。在许多ARM系统中,可以在统一的二级缓存的支持下拥有不同的指令和数据一级缓存。缓存需要保存一个地址、一些数据和一些状态信息。32位地址的顶部位告诉高速缓存信息来自主内存的位置,称为标记。总缓存大小衡量了它可以保存的数据量;用于保存标签值的ram不包括在计算中。但该标记确实占用了缓存中的物理空间。为每个标签地址保存一个数据字是低效的,因此通常将多个位置组合在同一个标签下。该逻辑块通常称为缓存行(cache line)。地址或索引的中间位标识行。该索引用作高速缓存的地址,不需要存储作为标记的一部分。本章后面会详细介绍。当缓存行包含缓存的数据或指令时,我们说它是有效的,而当它没有包含缓存的数据或指令时,我们说它是无效的。这意味着地址的底部几位(偏移量)不需要存储在标签中——你需要的是整行的地址,而不是一行中每个字节的地址,因此最低5或6个有效位总是0。与每一行数据相关联的是一个或多个状态位。通常,你会有一个有效的位,它将行标记为包含可使用的数据。(这意味着address标签代表一些真实的值。)在数据缓存中,还可能有一个或多个脏位,标记缓存行(或其中的一部分)保存的数据是否与主内存的内容不同(更新)。
[外链图片转存中…(img-x3bVxXIp-1698726497830)]