CPU组成原理基本概念梳理

1.字节

8位二进制代码表示一个字节byte

2.字-存储字

计算机字长32位,64位,就是4个字节,8个字节

3.数据字

一个数就是一个存储字

指令字

一条指令就是一个存储字

机器字长

计算机一次能直接处理的二进制位数

半字长

字长等于半个机器字长

双字长

字长等于两个机器字长

4.操作码

不同指令操作码不同

地址码

参与操作的操作数的地址码

5.操作码编码

固定长度操作码:如果一共64条则需要6位二进制编码

程序状态字(Program Status Word, PSW):
表示程序运行状态的一个二进制位序列。一般包含一些反映指令执行结果的标志信息(如:进位标志、溢出标志、符号标志等)和设定的一些状态信息(如:中断允许/禁止状态、管理程序/用户程序状态等)。
程序状态字寄存器(Program Status Word Register, PSWR):
用来存放程序状态字的寄存器。
标志寄存器(Flags Register):
80x86体系结构中用来表示程序状态和标志的寄存器。
堆栈(Stack):
堆栈是一块特殊的存储区。采用“先进后出”的方式进行访问。主要用来在程序切换时保存各种信息。栈底固定不动,栈顶浮动,用一个专门的寄存器(SP)来作为栈顶指针。从堆栈生长的方向来分,有“自顶向下”和“自底向上”两种堆栈。从堆栈的位置来分,有硬堆栈和软堆栈。硬堆栈的堆栈区由寄存器实现,软堆栈的堆栈区由内存区实现。
堆栈指针(Stack Pointer, SP):
是一个特殊的地址寄存器,用来存放堆栈的栈顶指针。如果是硬堆栈的话,栈顶指针是栈顶寄存器的编号;如果是软堆栈的话,栈顶指针是栈顶内存单元的地址。

我们知道,指令和数据是无差别的存放在存储器中的,那么当CPU或者说(控制器)从存储器中某地址的数据取出来后,CPU是如何区分该数据究竟是指令要放入指令寄存器(IR),还是数据(要放入对应的数据寄存器)呢?

实际上计算机可以从两个方面来做区分,分别是时间和空间。

1.时间。在取指周期(或取值微指令)取出的为指令,在指令执行周期(或相应微程序)取出(或写入)的为数据。

2.空间(或者叫地址来源)。由PC提供存储单元地址的取出的是指令,由指令地址码部分(Add(IR))提供存储单元地址的取出的是操作数。内存取出指令送控制器,而指令执行周期从内存中取的数据送运算器、往内存写入的数据也是来自于运算器。

那么CPU如何区分取指周期还是指令执行周期呢?

这里又要涉及几个概念了。

晶振:
在实际的计算机中并没有时钟这个东西,只有晶振,晶振,平时所说的时钟频率就是晶振的频率,这个参数与具体使用的晶振有关。那什么是晶振呢?为什么说时钟频率就是晶振的频率呢?

晶振:在主板上有一个长方形、用金属包裹的晶振元件,当主板加电后,它就会发生电磁振荡,产生一个高频电子脉冲信号(晶体振荡器控制着时钟速度,在石英晶片上加上电压,其就以正弦波的形式震动起来,这一震动可以通过晶片的形变和大小记录下来。晶体的震动以正弦调和变化的电流的形式表现出来,这一变化的电流就是时钟信号。)。但这些脉冲还不够精确,与电脑需要的频率还不匹配,因此需要将这些原始频率输入到晶振元件附近的时钟频率发生器芯片,对原始频率进行整形、分频,然后变为计算机需要的各种总线工作频率。计算机当中的总线采用分层结构,运行频逐层降低。

第一级:CPU与北桥芯片的数据传输通道,即系统前端总线频率;

第二级:内存与北桥芯片的数据传输通道,即内存总线频率;

第三级:AGP显卡与北桥芯片的数据传输通道,即AGP总线频率;

第四级:PCI、ISA设备与南桥芯片的数据传输通道,即PCI总线频率。

  • 主频:

CPU主频就是指CPU的时钟频率,就是CPU的工作频率。

  • 外频:

就是系统总线的工作频率。

倍频:
是指CPU主频与外频的相差倍数。或者说基频以外能产生的整数倍频率。用公式表示就是:主频=外频×倍频。

在电子电路中,产生的输出信号频率是输入信号频率的整数倍称为倍频。假设输入信号频率为n,则第一个倍频2n,相应地3n, 4n……等均称为倍频。在电脑CPU中,主频=外频x倍频。

时钟周期:
也称为振荡周期,节拍脉冲或T周期,定义为时钟脉冲的倒数(例如12M的晶振,它的时间周期就是1/12 us),是计算机中最基本,最小的时间单位,也是处理操作的最基本单位。在一个时钟周期内,CPU仅完成一个最基本的动作。

扩展:在一个时钟周期内,CPU仅完成一个最基本的动作。对于某种单片机,若采用了1MHZ的时钟频率,则时钟周期为1us;若采用4MHZ的时钟频率,则时钟周期为0.25us。由于时钟脉冲是计算机的基本工作脉冲,它控制着计算机的工作节奏(使计算机的每一步都统一到它的步调上来)。显然,对同一种机型的计算机,时钟频率越高,计算机的工作速度就越快。但是,由于不同的计算机硬件电路和器件的不完全相同,所以其所需要的时钟周频率范围也不一定相同。我们学习的8051单片机的时钟范围是1.2MHz-12MHz。

在8051单片机中把一个时钟周期定义为一个节拍(用P表示),二个节拍定义为一个状态周期(用S表示)
 

虽然指令和数据存放的格式一样,但是访问他们的时机不同。在取指令时期,cpu通过指令流取指令,存放在指令寄存器, 
然后解释并执行指令;在执行指令时期,cpu通过数据流取数据, 存放在数据寄存器。 所以指令流取的是指令,数据流取的是数据。

人们把内存的某个地址规定为起始地址(又称为复位地址),也就是说,当计算机开机或者被强行复位(也就是机箱上那个重启动按钮按下的的时候),CPU立即跳转到这个地址中,并且把它里面的代码作为指令来执行,同时根据这个指令的长度和格式判断下一条指令在什么地方。
  对于X86系列CPU(也就是现在人们常用的什么奔XX、赛XX系列),它的复位地址是FFFF0,如果表示成逻辑地址则是:FFFF:0000。对DEBUG比较熟悉的朋友或者会在一些高级语言中嵌入汇编语言的朋友可以这样做一个试验:
  用DEBUG执行一条指令(这是一条无条件跳转指令):jmp
FFFF:0000,或者在高级语言中嵌入这条汇编指令,执行后,你就会发现,计算机重新启动了(纯32位windows是不能进入实模式的,重启以后到载入WINDOWS以前都是实模式,只有实模式才能重启)。其实,用程序控制计算机重启的最本质的操作就是这样的。
 

就是我把数据和指令分开存就行了呀!于是就有了数据段

8086的CPU的模型,上面的提到的代码段,CPU用CS:IP寄存器来表示,数据段用DS:DI寄存器来,同时怕你还有复制的需求,于是又多了一对寄存器ES:SI,这样还剩最后一对栈段寄存器SS:SP ,还有用来存循环次数的寄存器叫做CX寄存器。还有一些CPU附带的寄存器

16位的CPU访问内存都是自由的,但是如果有了操作系统的出现,你说你改了操作系统的代码,那么操作系统就有可能直接崩溃了,那你还怎么玩,黑客想干嘛就干嘛,于是32位的寄存器才原来的基础上加了内存的访问的限制,但是原来16位的CPU被扩展成32位的CPU,寄存器的位数也是变大了。访问内存的方式也有所改变。我们先来说说内存的访问的限制吧!我们先不看对应的实现。我们先来想想,如果你来做,你该怎么做?那么我们需要这个程序的能够访问的内存的范围以及它的基地址,同时需要对这段内存的有哪些权限,读、写、执行等等权限。既然我们知道CPU的位数上去了,我们可以使用对应的位来表示对应的功能,于是就有了对应的描述的方式,在32位的CPU中叫做GDT(全局描述符)

寄存器GDTR,这个寄存器是48位,GDTR寄存器是48位的寄存器,低16位存的是全局描述符表边界,高32位存的是全局描述表线性基地址,其中全局描述符表边界等于GDT的表项乘8减去1

每个任务都有一个虚拟内存空间,对应的内存空间去对应的页映射表中找到对应的物理内存,通过这种简单的分页的方式,达到内存的最大化的利用,每个页都有4K,对于操作系统来说,如果一个任务执行完,操作系统就会对这个任务的物理内存的空间进行回收。

由于L1 Cache是最靠近处理器的存储器,因此其速度需要最大程度接近处理器的速度,这限制了其容量,同时为了达到这个目的,L1 Cache一般都是使用SRAM实现

相对于一般的处理器,超标量处理器对Cache的要求更高:对于ICache而言,需要实现每周期读取多条指令;对于DCache而言,则需要其每周期支持多条load/store指令的访问,也就是需要多端口的设计。尽管在超标量处理器中,多端口的部件有很多,但是这些器件本身的容量并不大,因此采用多端口设计也不会占用太大空间。而DCache的容量本身比较大,直接采用多端口的设计,其就会占用过大的硅片面积,并因此产生过大的访问延迟。由于load指令一般处于相关性的顶端,因此这会给处理器的性能带来负面的影响,因此ICache与DCache的设计思路是不一样的。

而L2 Cache则并不需要多端口的设计,延迟也不如L1 Cache重要,最重要的则是其命中率,因为在两级Cache的架构中,若L2 Cache无法命中,一般就需要去访问物理内存(一般是DRAM),其访问时间会非常长。

Cache由两部分组成:Tag与Data,其中Data部分用来保存一片连续地址的数据,而Tag部分则存储这片连续数据的公共地址,一个Tag与其对应的Data构成的一行称为一个Cache Line,而Cache Line中的数据部分称为数据块(Data Block),如果一个数据可以存储在Cache中的多个地方(一般是多路设计的情况下),这些被同一个地址找到的多个Cache Line称为一个Cache Set

影响Cache缺失的原因可以概括为以下三种:

  1. 强制缺失(Compulsory):由于Cache只是缓存以前访问过的内容,因此第一次被访问的指令或数据肯定不会在Cache中,因此,这个缺失是肯定会发生的,不过可以采用预取(Prefetching)技术在一定程度上降低这种缺失发生的频率。
  2. 容量缺失(Capcity):Cache容量越大,就可以缓存更多的内容,因此容量是影响Cache缺失发生频率的一个关键因素。
  3. 冲突缺失(Conflict):为了解决多个数据映射到Cache中同一个位置的情况,一般使用组相连结构的Cache,但由于面积和延迟限制,其相连度不可能很高。若一个程序频繁使用的几个数据同属于一个Cache set,同时其数量高于相连度,就会导致缺失率大大提升,为此,可以使用Victim Cache来缓解这个问题。

在实际实现中,Tag和Data部分实际上是分开的,分别叫做Tag SRAM和Data SRAM。

对于这种实现,可以采用并行访问(即同时访问Tag SRAM和Data SRAM)及串行访问(即先访问Tag SRAM再访问Data SRAM)方法。

对于并行访问方法而言,在读取Tag的同时,需要将每一路Index对应的的Data部分全部读取出来,然后送到多路选择器上,这个多路选择器受到Tag比较结果的控制,选出对应的Data Block,然后根据存储器地址中Block Offset的值,选择出合适的字节,一般将选择字节的这个过程称为数据对齐(Data Alignment)。Cache的访问一般都是处理器中的关键路径(Critical Path),这种方式在现实中如果在一个周期内完成访问的话会占据很大的延迟,因此就需要进行流水化处理。对于ICache而言,其影响不会太大,依然可以实现每周期读取指令的效果;而对于DCache而言,则会增大load指令的延迟,从而对处理器的性能造成负面影响

并行访问方式相比于串行访问方式而言,会有较低的时钟频率和较高的功耗,但是访问Cache的时间缩短了一个周期,但考虑在乱序执行的超标量处理器中,可以将访问Cache的这段时间通过填充其它的指令而掩盖起来,所以对于超标量处理器来说,当Cache的访问处于处理器的关键路径上时,可以使用串行访问的方式来提高时钟频率,同时并不会由于访问Cache的时间增加了一个周期而引起性能的明显降低;而对于顺序的处理器而言,并行访问方式则相对来说更合适

Cache的写入策略

由于一般ICache不会被直接写入内容,即使有自修改(Self-modifying),也通常是借助DCache实现的,因此,这里仅讨论DCache的写入策略。

DCache的写入策略可以总结为写通(Write Through)和写回(Write Back)。所谓写通是指,对Dache的所有写入操作会被同时在其下级存储器上执行,但由于下级存储器的访问时间一般来说比较长,而store指令在程序中出现的频率又比较高,这样必然会导致处理器的执行效率下降;所谓写回则是指,数据写到DCache后,对应的Cache Line会被标记为Dirty,只有当这个Cache Line被替换时,其数据才会写入下级存储器,这种方式会大大提升处理器的执行效率,但是会造成DCache与下级存储器的数据不一致(Non-consistent)问题。

上面的讨论都是假设在写DCache时,要写入的地址已经存在与DCache中,但事实上这个地址有可能并不存在于DCache中,这就发生了写缺失(Write Miss),这种情况的处理策略也可以总结为两种:Non-Write Allocate与Write Allocate。所谓Non-Write Allocate是指,直接将数据写到下级存储器中,而并不写到DCache中;所谓Write Allocate是指,首先将写入地址对应的整个数据块取回DCache中,然后再将写入到DCache中的数据合并到这个数据块中,之所以需要先取回,是因为一次写操作的数据量远远小于一个数据块的大小,如果不进行取回则直接写入DCache并标记Dirty,后期写回处理器时,必然会造成其周围的数据被破坏。一般来说,写通总是配合Non-Write Allocate使用,而Write Back则通常和Write Allocate配合使用。可以看出,Write Back与Write Allocate配合的方式设计复杂度是最高的,但是其效率也是最好的

提高Cache的性能

在实际的的处理器中,会采用一些更复杂的方法提高Cache的性能,包括写缓存(Write Buffer)、流水化(Pipelined Cache)、多级结构(Multilevel Cache)、Victim Cache和预取(Prefetching)等方法,除此之外,对于超标量处理器而言,还有非阻塞(Non-blocking)Cache、关键字优先(Critical Word First)和提前开始(Early Restart)等方法,这里主要介绍前几种方法。

Inclusive的缺点在于,其一份数据同时保存在两个地方,比较浪费硬件资源,但其最大的优点在于,简化了一致性(coherence)的管理,例如在多核的处理器中,当其中一个处理器改变了存储器中一个地址的数据时,如果在其它处理器的私有Cache(一般在多核处理器中,L1 Cache和L2 Cache都是私有的)中也保存了这个地址的数据,那么需要将它们置为无效,以避免这些处理器使用到错误的数据。如果是Inclusive类型的Cache,那么只需要检查最低一级的Cache即可,否则需要同时检查L1与L2 Cache,由于L1 Cache在处理器流水线的关键路径上,这会影响到处理器的执行效率;而Exclusive类型的Cache避免了硬件的浪费,由于Cache容量的大小直接影响处理器的性能,在同样的硅片面积下,Exclusive类型的Cache可以获得更多可用的容量,在一定程度上提高了处理器的性能,不过现代的大多数处理器都采用了Inclusive类型的Cache。

Victim Cache

有时候Cache中刚刚被替换掉的数据可能马上又要被使用,例如若一个CPU使用了2路组相连的DCache,而一个程序频繁使用的3个数据又恰好位于同一个Cache Set中,那么就会导致一个way中的数据经常被替换掉,然后又经常被写回Cache,这会导致处理器的执行效率大大下降,而为此增加way的个数通常又是不值得的,因为其它Cache Set未必有这样的特征,因此采用Victim Cache保存最近Cache替换掉的数据。通常Victim Cache采用全相连的方式,其容量都比较小(一般可以存储4~16个数据)

现代的大多数处理器中都采用了Victim Cache。

还有一种类似的设计思路,称为Filter Cache,只不过它放在Cache的前面,而Victim Cache则是在Cache之后。当一个数据第一次被使用时,它并不会马上被放到Cache中,而是首先放到Filter Cache中,等到这个数据再次被使用时,它才会被搬移到Cache中,这样做可以防止那些偶然被使用的数据占据Cache,从而提高Cache的利用效率,其原理如下:

多端口Cache

在超标量处理器中,为了提高性能,处理器需要能够在每个周期同时执行多条load/store指令,这就需要一个多端口的DCache,但由于DCache的容量比较大,采用多端口设计,会对芯片的面积和速度带来很大的负面影响,因此就需要采取一些策略解决这个问题,这里介绍三种方法:True Multi-port、Multiple Cache Copies和Multi-banking。

Multi-banking

这种结构被广泛用于现代处理器中,它将Cache划分为几个小的bank,每个bank都只有一个端口,如果在一个时钟周期内,Cache的多个端口上的访问地址位于不同的bank之中,那么这样不会引起任何问题,只有当两个或者多个端口的地址位于同一个bank中时,才会引起冲突,成为bank冲突(Bank Conflict)。

在这种方法中,一个双端口的Cache仍然需要两个地址解码器、两个多路选择器、两套比较器和两个对齐器,但是Data SRAM此时不需要实现多端口结构了,这样就提高了速度,并在一定程序上减少了面积。但由于需要判断Cache的每个端口是否命中,所以Tag SRAM仍然需要提供多个端口同时读取的功能,也就是需要采用多端口SRAM来实现,或者采用将单端口SRAM进行复制的方法


 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值