8

深入理解计算机系统(4.1)---X86的孪生兄弟,Y86指令体系结构

 2 years ago
source link: https://www.cnblogs.com/zuoxiaolong/p/computer21.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

  各位猿友们好,计算机系统系列很久没更新了,实在是抱歉之极。新的一年,为了给计算机系统系列添加一些新的元素,LZ将其更改为书的原名《深入理解计算机系统》。这本书非常厚,而且难度较高,LZ看了很久才看了四章。当然,这跟LZ最近很久没翻书有关系,最近公司的事情比较多,可让LZ愁了个愁,尤其是招人的事一直不太顺利,很多工作无法展开,也让LZ的心中一直压着一块大石。

  不过事情多了,就意味着责任大了,因此LZ最近经常回家自己研究公司所用的框架,以期了如指掌,可以应付各种随即事件。这耽误了LZ不少功夫,最近看书的激情在慢慢下降,这绝对不是个好事,要好好调整,毕竟艺多不压身,尽管计算机系统的这些知识在平时的用处不大,但是对自身的积累还是有很大好处的,因此建议各位猿友千万不要落下。不过耽误了这么久,说不定已经有猿友将LZ远远抛在身后了。

  好了,回归正题,来看看我们的Y86吧。

Y86指令体系结构

  Y86是一个指令体系结构(ISA),它是计算机系统这本书的作者YY出的指令集。目的是为了让我们更加清晰的了解ISA,就像你读编译原理,作者会教你做个编译器,是一样的道理。

  我们学这个并不是为了设计指令集,因为这种工作几乎不可能发生在我们的身上。还是和编译原理一样,你的工作也不太可能是去写一个编译器,创造一种语言,最多就是写个小例子拿来唬唬你身边的妹子或基友。我们的目的是为了了解CPU处理指令的流程以及它的工作原理,学习它的思想,这对你以后的技术之路说不定会有一些启发。很多时候,这种启发是很重要并且难得的,非神人不能达到。

  对于Y86,LZ也没有太多可介绍的,它就是一个ISA的例子,让各位通过它来了解ISA的设计。这一章的内容比较轻松,因为我们已经在第三章了解过X86的汇编指令,所以这里很多内容LZ只是一图代过,更多精彩内容还是要在后面再展现出来。

猿友们看的见的东西

  计算机是一个神秘的家伙,它的很多秘密我们都看不到,不过有了ISA的帮忙,我们就可以了解到很多计算机的秘密。比如LZ现在写博文的时候,CPU到底在干什么呢?

  理论上来讲,我们在编写一个程序的时候,我们是可以知道CPU的状态的。因为在你观察程序的汇编指令时,你可以知道当程序执行到某个地方,寄存器、存储器以及条件码寄存器等等的状态是如何的。说到底,无论是寄存器,存储器还是条件码寄存器等等,都是汇编指令可以访问的处理器状态。在设计和实现一个处理器的时候,只要我们能保证机器级程序(比如汇编程序)可以正常的访问程序猿可见状态(比如寄存器、存储器),那么就不太需要非得按照ISA真正的方式来表示我们的处理器状态。

  对于Y86来说,它的程序猿可见状态就是这几种:寄存器、存储器、条件码、PC、程序状态。

  在Y86当中,寄存器依旧是8个,每一个寄存器可以存储一个字,也就是一个32位二进制。条件码是一个一位二进制的寄存器,保存着最近的算术或逻辑运算所造成的影响的信息。PC则是程序计数器,记录当前正在执行的指令的地址。

  存储器则是一个很大的字节数组,Y86的程序可以使用虚拟地址(类似于数组的下标)来访问存储器,硬件和操作系统会将虚拟地址翻译为实际的地址。最后一个程序状态(stat),它则代表着程序的运行情况。

  以上便是程序猿可见的状态,或者说机器级程序可访问的CPU状态,我们在设计和实现一个处理器的时候,就是设计一系列指令去操作这些状态。

Y86指令集

  接下来我们就看看Y86的指令集,这里LZ就直接上图了,这些指令其实都是从X86的指令集YY而来。

  上面的指令相信大家都不会太陌生,LZ这里就不仔细的解释了,下面我们只简单的把每个指令的作用过一遍。

  halt:这个指令将会终止指令的执行。

  nop:这是一个占位指令,它不做任何事情,后续为了实现流水线,它有一定的作用。

  xxmovl:这是一系列的数据传送指令,其中r代表寄存器,m代表存储器,i代表立即数。比如rrmovl指令,则代表将一个寄存器的值,赋给另外一个寄存器。

  opl:操作指令,比如加法,减法等等。

  jxx:条件跳转指令,根据后面的条件进行跳转。

  cmovxx:条件传送指令,后面的xx代表的是条件。特别的是,条件传送只发生在两个寄存器之间,不会将数据传送到存储器。

  call与ret:方法的调用和返回指令。一个将返回地址入栈,并跳到目标地址。一个将返回地址入PC,并跳到返回地址。

  push与pop:入栈和出栈操作。

  这里LZ还要说的一点是,在图的右边,是指令所占的字节数或者说编码。一般两个寄存器占用一个字节,存储器则占用四个字节,指令的编码和功能占用一个字节。因此可以看到,比如rrmovl指令,它的字节长度是2,其中第一个字节代表了指令rrmovl,第二个字节代表了两个寄存器。

  对于opl、jxx、cmovxx指令来说,都有一个fn标识,占用4个二进制位(半个字节)。这个便是指令的功能部分,这个是由于它们的指令编码一样,但功能有所不同所造成的。比如对于opl,就有加、减、与、异或等操作,那么它们的指令编码第一个字节就分别为十六进制的60、61、62、63。

  对于寄存器的表示,是使用4个二进制位表示的,这是一个ID标识。所有的寄存器可以看做是一个寄存器文件,其中的ID标识就类似于它们的地址。对于一些只需要一个寄存器的指令来说,另一个寄存器标识位使用0xF表示。

  还有的指令需要一个字的常数,比如irmovl指令,call指令等等。这种指令,将把常数放在最后的四个字节当中,顺序按照大端法或小端法表示(与机器和OS有关)。对于call指令来说,这四个字节就是一个地址,这个地址就是绝对地址,指向了存储器当中的某一个位置,这个位置存储着代码。采用绝对地址是为了描述简单,真实当中,是采取的基于PC的相对地址。

Y86异常

  对于Y86来说,程序猿可见的状态中就有stat状态码,它标识了程序执行的状态。Y86需要有能力根据stat去做一些处理。不过为了简单起见,这里除了正常执行之外,都将停止指令的执行。真实当中,会有专门的异常处理程序。

  Y86有四种不同的状态码,AOK(正常)、HLT(执行halt指令)、ADR(非法地址)和INS(非法指令)。

Y86程序

  书中给出了一个示例程序,来说明X86和Y86的区别,这里LZ就不详细分析这些汇编指令了,这种事情在第三章已经做的很多了,各位猿友可以私底下自己分析一下。其实两者是非常相似的,毕竟Y86就是根据X86的结构YY出来的。区别就在于,有的时候Y86需要两条指令来达到X86一条指令就可以达成的目的。

  比如对于X86指令中的 addl $4,%ecx 这样的指令,由于Y86当中的addl指令中不包含立即数,所以Y86需要先将立即数存入寄存器,即使用irmovl指令,然后再使用addl来处理加法运算。

  总的来说,Y86就是一个X86的缩减版,它的目的是以简单的结构实现一个处理器,帮助我们了解处理器的设计和实现。有兴趣的猿友可以去观摩一下Y86程序生成的汇编代码,并进行逐一的分析,实际上,这与X86是十分类似的。

  本文的难度并不高,只是简单的介绍了一个类X86的指令集结构。接下来的内容需要我们了解一下具体的设计是如何进行的,以及如何使用硬件控制语言HCL。后面的内容相对来说会比较难理解,LZ在读的时候也是有点一知半解,尽管现在已经基本摸清了套路,但还是希望各位猿友在看的过程当中最好有自己的理解。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK