[A-01] ARMv8/ARMv9-Cache的基本架构

ver 0.2
在这里插入图片描述

更多精彩内容,请关注公众号

前言

在写虚拟化方面的文章,最近写到了内存模型这一块,心里有些犹豫到底要不要把存储这一方面的东西系统的总结一下,因为它们很重要,也很有趣。最后,决定另开一个ARM的系列专门的写写ARM体系的文章。ARM的体系庞大而复杂,涉及到的知识体系覆盖软件和硬件,我们就慢慢的聊吧,希望大家能够多提意见。从哪儿说起呢?就从签字售书说起吧,哈哈哈,先来聊聊cache。吸取之前文章的经验,会尽量压缩每一篇文章的体量,这样大家读起来也会轻松一些。整个Cache相关的文章大概会分成如下几个部分展开
(1) Cache的基本架构,介绍Cache诞生的背景、Cache的基本结构、Cache相关的术语。
(2) Cache的结构,详细介绍Cache的结构是如何设计,介绍相关的设计模式,如VIPT,PIPT等。
(3) Cache的策略, 介绍Cache使用中的一些相关策略,例如何如替换Cache中的数据等。
(4) Cache的一致性问题,例如,CPU-Cores之间如何共享数据,并保持一致,还有Cache和设备中(DMA)的数据保持一致等。

正文

在计算机系统中,存储器就是能够暂时或者永久的存储指令和数据的电子元件,在讲述cache之前先来了解一下围绕soc的存储器件,让大家有一个整体的概念。

存储器分类

从CPU的视角看过去,存储器可以分为5个级别,如图1-1所示。
存储器分离

图1-1 存储器的分类

下面我们来简要介绍一下各类型的存储器:
寄存器(Register):寄存器与其说是存储器,其实更像是 CPU 本⾝的⼀部分,只能存放极其有限的信息,但是速度⾮常快,和CPU的时钟周期几乎同步。而时钟周期又和CPU的主频相关,一个2GHz的CPU,时钟周期就是1/2G(0.5ns). 所以真的是很快。
⾼速缓存(CPU Cache):使⽤静态随机存取存储器(Static Random-Access Memory,简称SRAM)的芯⽚。也是我们今天的主角,在ARM体系下通常分为3个级别 L1、L2、L3. Cache的访问速度也很快,L1通常是2到4个时钟周期,L2通常是10到20个时钟周期,L3通常是20到60个时钟周期。
内存(DRAM):使⽤动态随机存取存储器(Dynamic Random Access Memory,简称DRAM)的芯⽚,⽐起SRAM 来说,它的密度更⾼,有更⼤的容量,⽽且它也⽐ SRAM 芯⽚便宜不少。当然它也更慢,每次的访问大概需要200到300个时钟周期。
硬盘:如固态硬盘(Solid-state drive 或 Solid-state disk,简称SSD)、硬盘(Hard Disk Drive,简称HDD)。硬盘大家就比较熟悉了,存储量大,但是访问速度最慢。内存要比SSD快10到1000倍,比HDD快10w倍。

下面我们用一张图来归纳一下存储器的特点,如图1-2所示,顺着箭头的方向,越往下存储的容量越大、访问的速度越来越慢、成本越来越低。每⼀种存储器设备只和它相邻的存储设备打交道。⽐如,CPU Cache是从内存⾥加载⽽来的,或者需要写回内存,并不会直接写回数据到硬盘,也不会直接从硬盘加载数据到CPU Cache中,⽽是先加载到内存,再从内存加载到cache中。
存储器的特点

图1-2 存储器的特点

甘蔗没有两头甜,访问越快的存储器价格越贵,而访问越慢的存储器价格自然也就更经济一些,我们通过一张图做一下对比,如图1-3所示。
价格对比

图1-3 存储器成本对比

这样看来,cache还是非常昂贵的,这里我们举一个例子给大家一个感性的认识,如图某通已经量产的8x55处理器CPU的cache配置,L1的size是保密的,L3是2MB,由于是big.little架构各个CPU-core的L2cache是不一样大的,如图1-4所示。从图中可以看出运算能力越强的Core,需要的数据和指令吞吐量就越大,因此需要的cache也就越大,下面章节我们会重点阐述一下基于AArch64的cache。
L2-cache-size

图1-4 主流的AArch64芯片L2-Cache Size

cache

cache的概念

我们上面花了一点时间介绍了围绕着soc的存储系统,下面我们复习一下SOC的架构(详细可以参考站里的文章<[V-02] 虚拟化基础-CPU架构(基于AArch64)>),如图1-5所示,可以看到A-Profile(CPU)、主存(RAM)、外设(Peripheral)等通过Interconnect(AMBA)总线连接到了一起。
在这里插入图片描述

图1-5 基于ARM的典型SOC架构

在时钟的同步下所有的节点就可以按照约定好的总线高低电平信号工作了。这里面A-Profile代表的CPU工作的时钟工作的频率非常高,也就是时钟周期非常小,达到几纳秒级别,而主存和外设可达不到这样快的速度,基本一次访问周期达到几百纳秒接近毫秒,大家差着数量级。这样的话CPU的性能就发挥就受到了外存和外设访问速度的限制,所以在设计CPU架构的时候,就需要引入一种机制缓解这个限制,最大限度发挥CPU的性能。这个机制就是在CPU的内部去增加一个memory单元支持接近CPU主频的高速访问,这块memory单元就是cache。这里我们引用一段手册的原文对cache的概念做一下更加精确的阐述。

A cache is a small, fast block of memory that sits between the core and main memory. It holds copies of items in main memory. Accesses to the cache memory occur significantly faster than those to main memory. Whenever the core reads or writes a particular address, it first looks for it in the cache. If it finds the address in the cache, it uses the data in the cache, rather than performing an access to main memory.

cache里面存储指令和数据,这些数据是内存里面的指令和数据的备份,由于从外部的低速存储设备换到了内部的高速存储设备。这样设计可以使CPU的core在每次取指令或者数据的时候会优先从高速的cache中搜索,如果不能命中,才会从外存中进行检索。arm处理器采用了多级缓存机制的设计,如图1-6所示。
arm cache

图1-6 ARM多级cache框图

在ARM处理器中,通常包括L1、L2和L3等多级缓存。其中,L1缓存是离处理器最近的缓存层级,容量较小但访问速度最快;L2缓存容量较大但访问速度稍慢;L3缓存则通常作为多个处理器核心共享的缓存层级,容量最大但访问速度相对较慢。前面的章节,已经了解到引入cache可以解决内存“墙”的问题,提高CPU的表现性能。到这里就要思考一个问题,为什么要引入多级cache机制? 这里先给出结论,这种多级缓存的设计主要是为了ARM处理器能够在不同的应用场景下实现高性能和低功耗的平衡,具体可以展开为如下几个方面:
(1) 降低功耗:通过引入多级缓存,各级的cache size有梯度的变大,处理器可以更加智能地管理数据的访问。当处理器需要访问某个数据时,它会首先逐级检查是否在缓存中存在该数据的副本。命中则直接从缓存中读取数据,避免直接的大范围搜索从而增大功耗。
(2) 提高缓存命中率:多级缓存设计使得每一级缓存都能够专注于存储一部分数据。当处理器需要访问某个数据时,它会首先尝试从最高级别的缓存(通常是L1缓存)中读取数据。如果未命中,则会依次检查下一级缓存,直到找到所需的数据或最终访问主存。这种设计提高了缓存的命中率,从而进一步提高了系统性能。
(3) 灵活性:多级缓存设计允许不同的缓存层级具有不同的特性,如容量、访问延迟和替换策略等。这使得ARM可以根据具体的应用场景和需求来优化缓存的设计,以实现最佳的性能和功耗平衡,最重要的是可以控制芯片本身的成本。

为啥要关注功耗:
芯片的功耗是指在运行过程中所消耗的能量,通常以瓦特(W)为单位衡量。随着功耗的增加,芯片在运行过程中会产生更多的热量,导致温度上升,而温度的升高又可能进一步增加功耗。然而,在过高的温度下,功耗可能会因为“温度反馈现象”而降低。这样不但会影响硬件设计,比如芯片内部的电路设计、片上电路设计、散热系统的设计,还会影响软件的设计。不管是移动的场景还是车载座舱或者是智能驾驶系统,为了保持芯片的稳定性和延长其使用寿命,以及成本控制,需要密切关注其功耗和温度,并采取有效的散热措施。

Cache的基本结构和术语

我们知道Cache缓存的是主存(内存、外存)里面的内容,自然被缓存的数据自然和内存中的数据要有一个映射的途径,通过这个途径彼此都能找到对方。内存是按照以字节为单位进行编码存储指令或者是指令执行的时候需要的数据,这样看来内存的地址就是最好的映射纽带连接起Cache和内存中的数据。基于这样的背景,我们来认识一下ARM中的Cache,如图1-7所示。
CacheStruct

图1-7 ARM Cache基本结构

通过观察Cache的结构,我们发现对于数据的组织形式,内存和Cache中还是很不一样的,Cache中的数据聚合度更高一些,而且设计出了的新的概念帮助表达这种数据的存储形式。
以下的行文中没有特殊说明,cache中的数据默认就代表内存中的数据和指令。

这些新的概念包括:TAG、Line、Index、Set、Way、Offset。下面我们将依托图1-7逐一说明。

(1)TAG(标记):
内存地址编码中的高端区域的一部分被称为TAG,图1-7中T-x都是一个个的TAG。关于TAG需要注意,TAG占用的存储空间不会计入cache的Size,例如,一个CPU-Copre的L2-Cache为256K,这256K是不包含存储TAG的区域的。

(2)Line(Cache Line/缓存行):
为了更加高效的操作和使用数据,Cache中是按照块(Block)的形式组织数据,一个块的数据组织在一个相同的TAG下面。例如图1-7中A-1 到 A-4中就存放这缓存的内存中的数据,这些数据按照块的形式组织在一起被成为Cache Line。当然,A-5 到 A8也是一个Cache Line,A9 到 A12 也是一个Cache Line,依次类推。关于Line还需要注意,我们还需要预留一些位标识一下Cache中数据的状态,例如是否和主存中的数据一致等。

(3)Index(索引):
内存地址编码中间区域的⼀部分,⽤于索引和查找地址在⾼速缓存⾏的哪⼀组中。图1-7中,A-1、A-5、A-9、A1-3分别在不同的Cache Line,就是通过Index进行区分的。

(4)WAY(路):
世界上本没有路,走的人多了便成了路。这里也一样,Cache-Line多了便成了路,图1-7中A-1、A-5、A-9、A1-3所在Cache Line共同组成了一路(way),这里就是路A,同理图中还有路B、C、D。需要注意的是,cache中的路必须是大小相同的才可以。

(5)Set(组):
图1-7的每一路有4个Cache Line,那么每条路(Way)的Index就是从0~3(0b00,0b01,0b10,0b11)就可以表达。那么路A、B、C、D中相同的Index就构成了组(Set).例如A-13、B-13、C-13、D-13所在的Line在路A、B、C、D中的Index都是3(0b11),那么A-13、B-13、C-13、D-13所在的Line就构成了一个组。

(6)Offset(偏移量):
内存地中的低端区域被称为Offset,其实就是Cache Line中的偏移量,CPU-Core可以按字节或字来寻址⾼速缓存⾏的内容。

这里面的核心其实就是⾼速缓存⾏(cache line),因为它是实实在在的存储这内存中数据的备份,常⻅的⾼速缓存⾏⼤⼩是32字节或64字节。其他元素设计出来都是为了能够让MMU能够快速的检索和定位Cache中的数据。下面我们引用手册中的描述,对Cache Line再做一下解释。

It would be inefficient to hold one word of data for each tag address, so several locations are typically grouped together under the same tag. This logical block is commonly known as a cache line, and refers to the smallest loadable unit of a cache, a block of contiguous
words from main memory. A cache line is said to be valid when it contains cached data or instructions, and invalid when it does not.

(7)Cache size
cache的⼤⼩称之为cahe size,代表cache可以缓存最⼤数据的⼤⼩. 例如一块芯片的一个CPU-Core的L2 Cache Size是256KB,如果此时Cache Line的Size我们设定为64字节。那么这个L2 Cache总共有 256K/64 = 256 x 1024 / 64 = 4096 条Cache Line。如果我们每个4条Cache Line 分成一路(way),那么这个L2 Cache就有4096 / 4 = 1024路(way),好多条路啊。

组关联映射与路(WAYS)

上一个小结,我们了解了cache的基本结构,搞清楚了基于ARM架构的Cache设计的一些基本要素的概念,而搞出这么多元素目的就是通过将内存地址切分开的方式将内存里面的内容映射到Cache中。我们已经了解了cache中way的基本概念,简而言之就是将cache分成同等大小进行切片,每一片就是一路。那么在工程实践中,将Cache那么分成多少片比较合适呢,依据又是什么?下面我们就围绕这个问题来展开讨论。这里先引入一个模型,如图1-8所示的2路模型,作为我们讨论问题的基础。这个模型的基本配置如下,2-ways、每条路有4个Cache Line、每个Cache Line可以保存16个字节的数据。
2 ways

图1-8 2路模型

Cache thrashing(Cache 抖动/Cache 震颤)
基于这个模型,我们假定没有Cache way 1,来推演一下,在执行运算的时候会发生哪些情况。此时,只有Cache way0 这一路Cahce,当我们要访问[0x0000.0000, 0x0000.0010)这连续16个字节中的数据的时候,不论是一个字节还是几个字节,此时要做的都是需要先从主存中将这16个字节的数据一起加载到Cache way 0的index(0b00)中,其他的根据局部性原理依次类推,将整个Cache way0填满。

过程一
此时Cache way0中的数据和主存中数据是如下的映射关系:
(1) [0x0000.0000, 0x0000.0010) 这连续16个字节中的数据放在 Cache way 0的index(0b00)。
(2) [0x0000.0010, 0x0000.0020) 这连续16个字节中的数据放在 Cache way 0的index(0b01)。
(3) [0x0000.0020, 0x0000.0030) 这连续16个字节中的数据放在 Cache way 0的index(0b10)。
(4) [0x0000.0030, 0x0000.0040) 这连续16个字节中的数据放在 Cache way 0的index(0b11)。

如果我们一直操作[0x0000.0000, 0x0000.0010)中数据,那么Cache way0中的数据是相对稳定的。这是,因为指令跳转或者数据访问,需要加载[0x0000.0040, 0x0000.0050) 中的数据,那么此时就需要做上面讨论中相同的动作,对Cache way0中的数据进行替换。

过程二
替换完成后Cache way0中的数据和主存中数据是如下的映射关系:
(1) [0x0000.0040, 0x0000.0050) 这连续16个字节中的数据放在 Cache way 0的index(0b00)。
(2) [0x0000.0050, 0x0000.0060) 这连续16个字节中的数据放在 Cache way 0的index(0b01)。
(3) [0x0000.0060, 0x0000.0070) 这连续16个字节中的数据放在 Cache way 0的index(0b10)。
(4) [0x0000.0070, 0x0000.0080) 这连续16个字节中的数据放在 Cache way 0的index(0b11)。

注意,Cache的详细替换策略我们会在后面文章详细阐述,这里简化了替换策略只是为了说明问题

如果此时程序需要访问主存 [0x0000.0080, 0x0000.0090) 中的数据,就需要进行新的一轮的替换(过程三)。当经历过程三之后,如果需要访问主存 [0x0000.0000, 0x0000.0010) 的数据,那么就要重复过程一,对Cache中的数据就行替换。然后Cache就会根据系统访问内存数据的情况,周而复始的不断的进行替换,而这个替换的情况是需要付出时钟周期代价,特别是重新访问之前加载到Cache中的数据,这种开销显然是我们不希望看到的。这个频繁的不断替换Cache中数据的过程就被称之为Cache thrashing(Cache 抖动/Cache 震颤)

优化替换过程
显然我们是不希望看到Cache抖动的,那么就要进行优化。这里我们增加一路,如图1-8所示,变成两路模型,看下效果。首先还是假定CPU要访问主存[0x0000.0000, 0x0000.0010) 中的数据,那么会展开第一轮替换过程。
优化后过程一
此时Cache way0中的数据和主存中数据是如下的映射关系:
(1) [0x0000.0000, 0x0000.0010) 这连续16个字节中的数据放在 Cache way 0的index(0b00)。
(2) [0x0000.0010, 0x0000.0020) 这连续16个字节中的数据放在 Cache way 0的index(0b01)。
(3) [0x0000.0020, 0x0000.0030) 这连续16个字节中的数据放在 Cache way 0的index(0b10)。
(4) [0x0000.0030, 0x0000.0040) 这连续16个字节中的数据放在 Cache way 0的index(0b11)。

如果我们此时要操作主存[0x0000.0040, 0x0000.0050) 中数据,因为Cache的架构进行了优化,此时我们有了两路Cache,那么此时Cache way0中的数据可以不动,放在那里,直接将主存[0x0000.0040, 0x0000.0050) 中数据放到Cache way1中。

优化后过程二
替换完成后Cache way0中的数据和主存中数据是如下的映射关系:
(1) [0x0000.0040, 0x0000.0050) 这连续16个字节中的数据放在 Cache way 1的index(0b00)。
(2) [0x0000.0050, 0x0000.0060) 这连续16个字节中的数据放在 Cache way 1的index(0b01)。
(3) [0x0000.0060, 0x0000.0070) 这连续16个字节中的数据放在 Cache way 1的index(0b10)。
(4) [0x0000.0070, 0x0000.0080) 这连续16个字节中的数据放在 Cache way 1的index(0b11)。

此时如果程序需要使用[0x0000.0000, 0x0000.0010) 中的数据,那么就不需要重复加载数据到Cache了,因为这些数据还在Cache way 0中,直接使用就好了。

上面这个思想实验,我们可以得出这样一个结论,就是在Cache中增加一路可以有效的减少Cache抖动进而提高整个系统的性能,那么是不是多增加路就可以了,其实也不尽然,因为每增加一路都会增加硬件的复杂度那么响应的成本就变高,功耗也会变高。那么回到本节开头的问题,到底多少路比价合适,这里不说过程只给结论(具体会因为Cortex-xx版本有差异): L1 的指令Cache和数据Cache是分开的,一般会有2路或者4路、L2 一般会有16路、L3 一般会比较大。

讲到这里我们也就清楚了为啥Linux Kernel中的代码要进行对齐了,特别是那些频繁使用的数据结构,能用共用体的尽量用共用体,能对齐的尽量对齐,其实底层的逻辑就是为了执行的效率,能在一个CacheLine中搞定就不要分散在多个CacheLine中,能在一路中搞定就不要分散到多个路中,因为这些情况发生了都会增加CPU Core访问数据的开销。

Cache的映射方式
到这里我们对Cache的映射方式做一个总结:CPU对内存中数据的访问不能跨越Cache,那么就引出了如何建立内存中的数据块和Cache中的数据块直接建立联系的过程,也就是建立映射关系的过程。明确了映射关系的意义之后,下一个课题就是通过什么方式建立映射,归纳下来有如下三种方式: 直接相联映射(Direct Mapped Cache)、全相联映射(Fully Associative Cache) 、 组相联映射(N-way Set Associative Cache)。

具体的分析如下:
(1) 直接相联映射(Direct Mapped Cache)
这种映射方式的最大特点就是,内存块和Cache块的是固定的映射关系。
例如图1-8中, Cache中只需要保留一路Cache way0,内存块[0x0000.0000, 0x0000.0010) 、[0x0000.0040, 0x0000.0050)、[0x0000.0080, 0x0000.0090) …依次类推都会被映射在同一个位置,那就Cache way0的Index(0b00)中。原因是,Cache way0中只有4路,每行的Cache Line的size为16个字节,那么主存中的地址的低4位[0b0000,0b1111]就可以进行Cache Line内部以字节为单位进行寻址了,到这里Offset就确认了。Cache way0有4行,那么内存地址中间区域的2位[0b00,0b11]就可以寻址Cache Line了,到这里我们就确定了Index。那么所有索引区域相同的内存块,都会被映射到同一个Cache Line上,比如,[0x0000.0000, 0x0000.0010) 、[0x0000.0040, 0x0000.0050)、[0x0000.0080, 0x0000.0090) 这些内存块的地址第5位和第6位都是0b00。那么这个映射模型就变成了这个样子:
(1) [0x0000.0000, 0x0000.0010)、[0x0000.0040, 0x0000.0050)、…这连续16个字节中的数据放在 Cache way 0的index(0b00)。
(2) [0x0000.0010, 0x0000.0020)、[0x0000.0050, 0x0000.0060)、…这连续16个字节中的数据放在 Cache way 0的index(0b01)。
(3) [0x0000.0020, 0x0000.0030)、[0x0000.0060, 0x0000.0070)、…这连续16个字节中的数据放在 Cache way 0的index(0b10)。
(4) [0x0000.0030, 0x0000.0040)、[0x0000.0070, 0x0000.0080)、…这连续16个字节中的数据放在 Cache way 0的index(0b11)。

设计这种映射方式的优点就是硬件电路设计简单,但是缺点就是会有Cache抖动。

(2)全相联映射(Fully Associative Cache)
这种方式的的最大特点是,内存块和Cache块是随机的、灵活的映射关系;
例如图1-8中, Cache中同样只需要保留一路Cache way0,同样是内存块的Size是16个字节,物理内存中的地址低四位[0b0000,0b1111]就可以进行Cache Line内部以字节为单位进行寻址。但是为了保证随机的映射特性,不需要Index区域进行Cache way0内部的行寻址了,此时内存块[0x0000.0000, 0x0000.0010)、[0x0000.0040, 0x0000.0050)可以映射到Cache way0的任何位置。也就是说此时内存地址的低4位用来进行Cache Line的行内存寻址,内存地址的高位全部变成TAG了。

设计这种映射方式的优点如果Cache的size足够大,Cache line的行数足够就是大大降低Cache抖动的风险,但是缺点就是硬件电路设计复杂、造价高、工程实践难度大。ARM的解释如下:

Increasing the associativity of the cache reduces the probability of thrashing. The ideal case is a fully associative cache, where any main memory location can map anywhere within the cache. However, building such a cache is impractical for anything other than very small caches, for example, those associated with MMU TLBs.

组相联映射(N-way Set Associative Cache)
这种映射方式就是结合前两种映射方式的优点,摒弃他们的缺点,是前两种⽅案的折中⽅法。
还是结合图1-8中的例子,其实我们在讲如何改善cache抖动的优化方案时,采用的就是组相联的映射方式。一方面,我们对固定映射方式做了改良增加了路数(每条路不能只是一行,如果增加了路数不增加,但是每条路只有一行,那也没有意义),那么内存块就可以映射到多个Cache块中,例如:
(1) [0x0000.0000, 0x0000.0010)、[0x0000.0040, 0x0000.0050)、…这连续16个字节中的数据放在Cache way 0和Cache way 1的index(0b00)。
(2) [0x0000.0010, 0x0000.0020)、[0x0000.0050, 0x0000.0060)、…这连续16个字节中的数据放在Cache way 0和Cache way 1的index(0b01)。
(3) [0x0000.0020, 0x0000.0030)、[0x0000.0060, 0x0000.0070)、…这连续16个字节中的数据放在Cache way 0和Cache way 1的index(0b10)。
(4) [0x0000.0030, 0x0000.0040)、[0x0000.0070, 0x0000.0080)、…这连续16个字节中的数据放在Cache way 0和Cache way 1的index(0b11)。
这样就兼顾前两种映射方式的优点,实际上ARM的Cache机制也是采用这是映射方式。

In practice, performance improvements are minimal for above 8-way, with 16-way associativity being more useful for larger L2 caches.

结语

本文我们介绍了计算机系统的存储相关的内容,并且讲述了Cache的基本架构以及基本结构中的组成元素,最后阐述了Cache内存块和内存块中的数据是如何映射的,并且介绍了ARM采用组映射的背景。为进一步介绍Cache的其他内容打下了基础。
Cache这一部分内容说实话其实是比较晦涩的,但是对于一个软件工程师还是比较有用的,如果不熟悉cache机制,就很难理解内核中的很多机制的设计背景,例如锁的机制,等等。本文就到这里,后续的文章我们会继续深入分析Cache的结构、工作原理、使用的策略、以及同步等方面的课题。

在这里插入图片描述

更多精彩内容,请关注公众号

Reference

[01] <DDI0487K_a_a-profile_architecture_reference_manual.pdf>
[02] <DEN0024A_v8_architecture_PG.pdf>
[03] <80-LX-MEM-yk0008_CPU-Cache-RAM-Disk关系.pdf>
[04] <80-ARM-ARCH-HK0001_一文搞懂CPU工作原理.pdf>
[05] <80-ARM-MM-Cache-wx0003_Arm64-Cache.pdf>
[06] <80-ARM-MM-HK0002_一文搞懂cpu-cache工作原理.pdf>

Glossary

SRAM - Static Random-Access Memory
DRAM - Dynamic Random Access Memory
SSD - Solid state disk
HDD - Hard Disk Drive
SOC - System on a chip
AMBA - Advanced Microcontroller Bus Architecture 高级处理器总线架构

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值