计算机组成
3 指令系统体系结构
3.5 MIPS体系结构
MIPS是精简指令系统的代表,采用了与X86相反的设计理念,并引领了精简指令系统的潮流,那就让我们一起来看一看这究竟是怎么一回事。
要探讨MIPS指令系统,就得从它的设计者John Hennessy开始说起。Hennessy 1977年进入斯坦福大学,81年领导了RISC微处理器研究小组,他也被称为RISC的先驱。RISC是精简指令系统计算机的简称。与之相对,之前的计算机上的指令系统就被称为复杂指令系统,X86就是其中的代表。后来,Hennessy 共同创立了MIPS计算机系统公司。90年代,他主要是在斯坦福计算机系担任系主任等职务,2000年起开始担任斯坦福大学的校长。由于他所设计的MIPS体系结构引领了精简指令系统的潮流,后来还获得了IEEE的荣誉奖章,而他所创立的MIPS公司也一度创造了辉煌。
在80年代末上市,后来被收购,然后再一次上市,再一次被收购。现在MIPS处理器已经不再应用在计算机产品中了,但是在广义的计算设备包括数字电视,游戏机,网络设备等领域仍然有广泛的应用,其实MIPS公司商业上的兴衰也是诸多 RISC微处理器公司的命运写照。
第一代的MIPS是32位的, 在1985年推出了对应的处理器,R2000;
90年,R3000处理器对应着第二代的MIPS;
92年,MIPS扩展到了64位;94年,64位的MIPS又进一步升级;
96年的MIPS5并没有对应的处理器;
然后在99年,MIPS指令系统进行了较大的调整,形成了MIPS32;
到了99年,以MIPS5为基础,推出了MIPS64指令系统。
MIPS的设计指导思想非常的简单,从它的名字就可以看出来。MIPS全称的含义是一个流水线不会互锁的微处理器。流水线是现代微处理器为提高性能而采用的一项技术,而流水线中的互锁则是导致流水线性能降低的一个非常重要的因素。从这个名称也可以看出,MIPS的指导思想是希望其指令的设计能让微处理器运行的更快,性能更好。所以它主要的关注点是减少指令的类型,并且降低指令的复杂度,所以在MIPS指令系统当中,指令的总数是很少的。而且每条指令都比较简单。它的主要目的就是希望可以用一个非常简单的CPU来支持这样的指令系统。而CPU越简单就可以运行的更快。假设要编写程序完成同样的任务,用MIPS指令编写,其指令数量是X-86指令的5倍,但是如果MIPS的CPU能够做到比X86 CPU快10倍,那它仍然获得了明显的性能优势。这就是MIPS,同时也是RISC的设计思想。
那MIPS的指令是怎么体现它这样的设计思想的呢?
第一,MIPS固定了指令的长度,都是32个比特,也就说MIPS中的一个WORD。我们要注意这和X86中一个WORD是16位是不同的。固定的指令长度,大大简化了CPU从存储器中取指令的工作。不用像X86 CPU那样需要判断每条指令的长度。
第二,MIPS采用了非常简单的寻址模式。相比于X86提供的复杂多样的寻址模式, 虽然给编程带来了不便,但是大大简化了CPU访问存储器的控制逻辑。
第三,MIPS指令的数量比较少,每条指令的工作也很简单。基本上一条指令只完成一个操作,不像X86的指令,一条指令往往完成丰富的功能,这样可以简化指令的执行过程。不但简化了CPU的控制逻辑,而且可以方便的实现各种让指令并行执行的技术,从而提高CPU的性能。
第四,在MIPS指令系统中只允许LOAD和STORE这两种指令访问存储器,而不支持X86指令中这些让算术指令访问存储器的操作,因为访存是一个相对复杂的工作。
这种限制就可以让运算指令的实现变得非常的简单。但是我们要注意,MIPS的这些特点让直接使用MIPS指令进行编程变得非常的困难,因此,想要有高效率的MIPS程序,必须要有优秀的编译器的支持。我们来看几个MIPS指令的例子。
例如加法指令,它的格式是ADD a, b, c
我们注意,与X86指令不同,MIPS的加法指令是三个操作数 a, b, c ,这三个操作数可以是三个寄存器。除了加法运算,这里还列出了减法,乘法,除法等等。还有逻辑运算,还有左移和右移这样的移位运算。这里我们可以看出MIPS的运算指令格式都非常简洁和统一,而且这些指令的操作数都不可以是存储器操作数。要访问存储器,就必须使用专门的访存指令。
我们来看一个例子,假设A是一个100个字的数组,它的首地址存放在19号寄存器中,MIPS的寄存器编号用$符进行标记。
那如果我们想完成 A[10] = h + A[3] 这样的运算,也就说将一个变量h加上数组A中的第三个元素,并赋给数组A的第十个元素。我们注意,变量h放在18号寄存器中,而我们可以使用8号寄存器用来存放临时数据。那么对应的MIPS指令需要如下几条:
首先要用LOAD指令,将19号寄存器对应的地址加上偏移量12,因为MIPS当中一个字是32位,所以第三个元素与首地址之间的偏移是12。将19号寄存器对应的地址加上偏移量12计算得到的存储器地址中的这个字装入到8号寄存器中,这就相当于将数组A中的第三个元素赋给了一个临时变量。
第二句是一个加法指令,将8号寄存器与18号寄存器相加, 并将结果存放在8号寄存器。这就相当于将数组A的第三个元素与变量h相加,还存在这个临时变量中。
第三条指令是将8号寄存器中的数,也就是运算的结果存到以19号寄存器为首地址,偏移量为40的内存单元,这就是数组A的第十个元素的位置。
那我们用这三条MIPS指令就完成了这个功能。
而这张表列出了MIPS的所有的通用寄存器,总共有32个,每个都是32位。相比于X86的寄存器,MIPS的通用寄存器是非常规整的。这32个寄存器的编号从0一直到31,那我们可以用$符加上编号进行指示。同时每个寄存器还有一个符号的名称,并且约定了一些特定的用途,例如8号到15号寄存器,又被称为t0到t7的寄存器,用来保存临时的变量。而1号寄存器,它的名称是 at,专门留给汇编器使用。
在编写汇编程序时,我们可以用数字,也可以用名称,来表示这些寄存器。例如 lw 这两条指令所表达的含义以及对应的二进制编码都是一样的。add 这两条指令也是如此。如果我们直接用MIPS指令进行汇编语言的编程,从t0到t7,s0到s7,这些寄存器都是我们经常使用的。MIPS 的体系结构简明扼要,需要说明的就是这些。
我们已经了解了MIPS的设计理念,那这样的理念究竟是如何实现的呢?在下一节我们将一起来探究MIPS的指令。