个人原创,转载请注明作者卫泽春
一、概念
1、程序工作在虚拟地址空间,需要通过MMU转化到实际物理内存去访问指令和数据;
2、指令的寻址方式,顺序寻址,执行完一个指令,接着执行下一条指令;跳跃寻址,执行完一个指令,接着执行非下一条指令,比如分支指令,函数返回指令等,中断和异常也是一种跳跃寻址;顺序寻址通过程序计数器自动加就可以找到要执行的指令;指令执行满足局部性原理,也就是刚执行完的指令,他附近的指令都最大概率会被再执行。
3、内存访问速度相对于处理器速度太慢了,而且内存种类也不同,计算机系统大多选择了多级存储系统,主要内存选择了成本较低,容量较大,速度相对慢的动态刷新特性的器件,增加了成本较高,容量较小,但速度较快,不用动态刷新的器件作为缓存,形成多级存储系统;
4、cache的原理是将buffer分成固定大小的数据块,经常是64字节或者32字节,叫cache line,然后索引cache line的实际物理内存基地址,供硬件进行快速查找。因此输入实际的物理地址,从cache中查找数据,如果发现,则返回数据,没有发现,则cache miss,去下级cache或内存中查找,并读入对应的cache line。如果cache 满了,则发生换页,一般算法是最近最少使用LRU。如果是写数据,则需要根据cache的write through还是write back,如果是write back,先写cache line,并标记cache line为脏,等换页时,回写到内存;如果是write through,则直接写到内存,并更新cache line。
二、处理器内核组成
处理器内核通常包括寄存器组,取指令单元,指令MMU,指令cache,指令解码,指令执行单元,数据加载存储单元LSU,数据MMU和数据cache,以及外部总线。从整个处理器看,是冯诺依曼体系,但是在内核中是哈弗结构,指令和数据单独处理。当指令和数据共享cache时,或者cache功能被禁止,就是冯诺依曼体系结构。当MMU被禁止时,就是实地址模式,否则是虚拟地址。
三、指令执行过程
首先指令的虚拟地址位于程序计数器寄存器内,取指令单元读取程序计数器寄存器的指令虚拟地址,发送到指令MMU单元,MMU根据指令虚拟地址查找到对应的TLB项,返回TLB中存储的实际内存地址,如果没有找到,继续查找L2 TLBs,如果L2找到对应的TLB项,将TLB换入L1 MMU中,并返回对应的实际内存地址。如果还没有查找到,需要软件协助发现对应的TLB项,如果软件也找不到,则说明访问非法指令。
如果MMU返回实际内存地址,再根据实际内存地址,去缓存cache中查找指令,缓存是根据指令的实际物理地址做索引的。如果指令位于cache中,即cache命中,返回cache中的指令;如果cache中没有该地址指令,即cache miss,处理器会去下一级cache或者内存中继续查找,如果找到,则将对应的cache块(也就是cache line)读入到L1 cache中,并返回查找地址的指令。
通常的情况,处理器内核提前读取跟在当前程序计数器中的指令后的几条指令,把这些指令缓存一个buffer中,这个就叫做指令预取,但是如果预取到的指令中含有跳跃指令,那么,跳跃指令后的指令将得不到运行,预取就失败了,于是处理器提前对预取的指令进行分析,查找跳跃指令,如果是跳跃指令,则预取跳跃后的指令。对于有条件跳跃,默认顺序执行,减少跳跃带来的系统开销。如果后面执行条件需要跳跃,则释放预取到指令,重新获取指令。
通常处理器都有多个实现不同功能的执行单元,能同时运行指令,比如有的实现算术逻辑运行,有的实现加载存储等。解码器从buffer中取出指令解码,然后分发给对应的执行单元执行。因为不同的执行可能花费的时间长度不一样,比如一个加法运算通常一个时钟周期就完成,但是一个乘法可能要花费四个,甚至更多的时钟周期。那么就有可能加法运算在乘法运算后开始执行,但是却先于乘法指令执行完。这个就是指令执行乱序。为了满足程序的设计结果正确,通常将指令的执行结果缓存起来,按照指令的设计顺序输出结果。
如果执行的指令是一个读取或者写数据结果到内存,那么首先根据访问的寻址地址到数据MMU中查找对应的物理地址,然后根据实际物理地址去数据cache中查找,如果cache hit,并且是读数据,那么就将cache中的数据放入寄存器;如果cache miss,那么先查下级cache,或者内存,如果hit,则将对应的cache line读入到数据cache中,并返回数据到寄存器中,如果都没有,则读取失败。如果是写操作,cache hit则根据cache 是write through还是write back分别处理,write back则是修改cache line中的数据,并把cache line标为脏,当执行cache换页时回写到内存,write through则是直接修改内存,并重新读入cache line。