2.3 指令系统发展历程
指令系统的发展经历了从简单到复杂,再从复杂到简单的演变过程。现代指令系统在指令内容、存储管理和运行级别控制等方面都产生了一系列变化,这些变化体现了人类对计算机体系结构这个学科认知的提升。
2.3.1 指令内容的演变
依据指令长度的不同,指令系统可分为复杂指令系统(Complex Instruction Set Computer,简称CISC)、精简指令系统(Reduced Instruction Set Computer,简称RISC)和超长指令字(Very Long Instruction Word,简称VLIW)指令集三种。CISC中的指令长度可变;RISC中的指令长度比较固定;VLIW本质上来讲是多条同时执行的指令的组合,其“同时执行”的特征由编译器指定,无须硬件进行判断。
早期的CPU都采用CISC结构,如IBM的System360、Intel的8080和8086系列、Motorola的68000系列等。这与当时的时代特点有关,早期处理器设备昂贵且处理速度慢,设计者不得不加入越来越多的复杂指令来提高执行效率,部分复杂指令甚至可与高级语言中的操作直接对应。这种设计简化了软件和编译器的设计,但也显著提高了硬件的复杂性。
当硬件复杂性逐渐提高时,CISC结构出现了一系列问题。大量复杂指令在实际中很少用到,典型程序所使用的80%的指令只占指令集总指令数的20%,消耗大量精力的复杂设计只有很少的回报。同时,复杂的微代码翻译也会增加流水线设计难度,并降低频繁使用的简单指令的执行效率。
针对CISC结构的缺点,RISC遵循简化的核心思路。RISC简化了指令功能,单个指令执行周期短;简化了指令编码,使得译码简单;简化了访存类型,访存只能通过load/store指令实现。RISC指令的设计精髓是简化指令间的关系,有利于实现高效的流水线、多发射等技术,从而提高主频和效率。
最早的RISC处理器可追溯到CDC公司和其1964年推出的世界上第一台超级计算机CDC6600,现代RISC结构的一些关键特性——如只通过load/store指令访存的load/store结构——都在CDC6600上显现雏形,但简化结构提高效率的思想并未受到小型机和微处理器设计者的重视。1975年,John Cocke在IBM公司位于约克镇的Thomas J.Watson研究中心组织研究指令系统的合理性并研制现代RISC计算机的鼻祖IBM 801,现在IBM PowerPC的主要思想就源于IBM 801。参与IBM 801项目的David Patterson和John Hennessy,分别回到加州大学伯克利分校和斯坦福大学,开始从事RISC-1/RISC-2项目和MIPS项目,它们分别成为SPARC处理器和MIPS处理器的前身。IBM 801的项目经理Joel Birnbaum在HP创立了PA-RISC,DEC公司在MIPS的基础上设计了Alpha处理器。广泛使用的ARM处理器也是RISC处理器的代表之一。David Patterson教授在加州大学伯克利分校推出的开源指令系统RISC-Ⅴ,是加州大学伯克利分校推出的继RISC-Ⅰ(1981年推出)、RISC-Ⅱ(1982年推出)、SOAR(1984年推出,也称为RISC-Ⅲ)、SPUR(1988年推出,也称为RISC-Ⅳ)之后的第五代指令系统。
RISC指令系统的最本质特征是通过load/store结构简化了指令间关系,即所有运算指令都是对寄存器运算,所有访存都通过专用的访存指令(load/store)进行。这样,CPU只要通过寄存器号的比较就能判断运算指令之间以及运算指令和访存指令之间有没有数据相关性,而较复杂的访存指令相关判断(需要对访存的物理地址进行比较)则只在执行load/store指令的访存部件上进行,从而大大简化了指令间相关性判断的复杂度,有利于CPU采用指令流水线、多发射、乱序执行等提高性能。因此,RISC不仅是一种指令系统类型,同时也是一种提高CPU性能的技术。X86处理器中将CISC指令译码为类RISC的内部操作,然后对这些内部操作使用诸如超流水、乱序执行、多发射等高效实现手段。而以PowerPC为例的RISC处理器则包含了许多功能强大的指令。
VLIW结构的最初思想是最大限度利用指令级并行(Instruction Level Parallelism,简称ILP),VLIW的一个超长指令字由多个互相不存在相关性(控制相关、数据相关等)的指令组成,可并行进行处理。VLIW可简化硬件实现,但增加了编译器的设计难度。
VLIW的思想最初由Josh Fisher于20世纪80年代初在耶鲁大学提出,Fisher随后离开耶鲁创立了Multiflow公司,并研制了TRACE系列VLIW处理器。后来Fisher和同样经历创业失败的Bob Rau加入了HP公司,并主导了HP在20世纪90年代的计算机结构研究。
同时,Intel在i860中实现了VLIW,这也奠定了随后两家公司在Itanium处理器上的合作关系,Itanium(IA-64)采用的EPIC结构的思想即来源于VLIW。
图2.2直观地给出了RISC、CISC、VLIW三种结构的指令编码。MIPS三种类型的指令内部位域分配不同,但总长度均为32位;X86不同指令的长度都可能不同;IA-64则将三条41位定长指令合并为一条128位的“束”。
图2.2 RISC、CISC、VLIW指令编码特点
2.3.2 存储管理的演变
存储器是冯·诺依曼结构计算机的核心部件,存储管理的演变是指令系统演变的重要组成部分。存储管理的演变经历了连续实地址、段式、页式虚拟存储等阶段。
连续实地址的管理方式是最早期也是最朴素的方式,各程序所需的内存空间必须连续存放并保证不与其他程序产生冲突。这种方式不但会带来大量的内存碎片,而且难以管理多个程序的空间分配。
段式存储管理将内存分为多个段和节,地址组织为相对于段地址的偏移。段式存储主要应用于早期处理器中,Burroughs公司的B5000是最早使用段式存储的计算机之一。Intel从8086处理器开始使用段式存储管理,在80286之后兼容段页式,但在最新的X86-64位架构中放弃了对段式管理的支持。
页式虚拟存储管理将各进程的虚拟内存空间划分成若干长度相同的页,将虚拟地址和物理地址的对应关系组织为页表,并通过硬件来实现快速的地址转换。现代通用处理器的存储管理单元都基于页式虚拟管理,并通过TLB进行地址转换加速。
页式虚拟存储可使各进程运行在各自独立的虚拟地址空间中,并提供内存映射、公平的物理内存分配和共享虚拟内存等功能,是计算机系统发展过程中具有里程碑意义的一项技术。
下面分别介绍上述几种存储管理方式的基本方法。
段式存储管理的地址转换过程如图2.3所示。虚拟地址分为段号和段内偏移两部分,地址转换时根据段号检索段表,得到对应段的起始物理地址(由段长度和基址可得),再加上段内偏移,得到最终的物理地址。需要注意的是,段表中存有每个段的长度,若段内偏移超过该段长度,将被视为不合法地址。段式存储中每段可配置不同的起始地址,但段内地址仍需要连续,当程序段占用空间较大时,仍然存在内存碎片等问题。
页式存储管理的地址转换过程如图2.4所示。虚拟地址分为虚拟页号和页内偏移两部分,地址转换时根据虚拟页号检索页表,得到对应的物理页号,与页内偏移组合得到最终的物理地址。
图2.3 段式存储管理的地址转换过程
图2.4 页式存储管理的地址转换过程
段页式管理结合了段式和页式的特点,其地址转换过程如图2.5所示,虚拟地址分为段号、虚拟页号和页内偏移三部分,地址转换时首先根据段号查询段表得到对应段的页表起始地址,再根据虚拟页号查询页表得到物理页号,与页内偏移组合得到最终的物理地址。段页式同样需要检查段地址的合法性。
图2.5 段页式存储管理的地址转换过程
2.3.3 运行级别的演变
作为软件指令的执行者,处理器中有各种级别的资源,比如通用寄存器、控制寄存器等。为了对软件所能访问的资源加以限制,计算机引入了运行级别的概念。运行级别经历了无管理、增加保护模式、增加调试模式、增加虚拟化支持等阶段。
早期的处理器和当今的嵌入式单片机中不包含运行级别控制,所有程序都可控制所有资源。无管理的方式在安全方面毫无保障,软件必须小心设计,确保不会相互干扰。这通常只在规模有限、封闭可控的系统如微控制器(Micro Control Unit,简称MCU)中使用。
现代操作系统(如Linux)包含保护模式,将程序分为两个权限等级:用户态和核心态。核心态具有最高权限,可以执行所有指令、访问任意空间。在用户态下,程序只能访问受限的内存空间,不允许访问外围设备。用户态程序需要使用外围设备时,通过系统调用提出申请,由操作系统在核心态下完成访问。保护模式需要硬件支持,如X86指令系统中定义了Ring0~Ring3四个权限等级,MIPS指令系统中定义了user、supervisor和kernel三个权限等级。LoongArch指令系统中定义了PLV0~PLV3四个权限等级,由当前模式信息控制状态寄存器(CSR.CRMD)的PLV域的值确定。在LoongArch处理器上运行的Linux操作系统,其核心态程序运行在PLV0级,用户态程序通常运行在PLV3级。
为了方便软硬件调试,许多指令系统中还定义了调试模式和相应的调试接口,如ARM的JTAG、MIPS的EJTAG。LoongArch指令系统定义了专门的调试模式、调试指令和配套的状态控制寄存器。在调试模式下,处理器所执行的程序将获得最高的权限等级,不过此时处理器所执行的指令是从外部调试接口中获得的,并且利用专用的控制状态寄存器使得被调试程序的上下文可以无缝切换。
虚拟化技术在服务器领域特别有用,一台物理主机可以支撑多台虚拟机,运行各自的系统。虚拟机不绑定底层硬件,可看作一个软件进程,因而部署起来非常灵活。虚拟机中同样要支持不同的运行级别,为了提高效率,硬件辅助虚拟化成为虚拟化发展的必然趋势。IBM System/370早在1970年就增加了硬件虚拟化支持;2005年以来,Intel和AMD也分别提出了硬件辅助虚拟化的扩展VT和SVM。ARM的AArch64架构也定义了硬件虚拟化支持方面的内容。这些指令系统在硬件虚拟化支持中引入了新的运行级别,用于运行虚拟机操作系统的核心态和用户态程序。
以LoongArch指令系统为例。其运行级别主要包括调试模式(Debug Mode)、主机模式(Host Mode)和客户机模式(Guest Mode)。主机模式和客户机模式又各自包含PLV0~PLV3四个权限等级,即具有Host-PLV0~Host-PLV3和Guest-PLV0~Guest-PLV3这8个运行级别。所有运行级别互相独立,即处理器在某一时刻只能存在于某一种运行级别中。处理器上电复位后处于Host-PLV0级,随后根据需要在不同运行级别之间转换。
不同运行级别可访问并控制的处理器资源不同,图2.6给出了这种对应关系的示意。其中调试模式下具有最高的优先级,可以访问并控制处理器中所有的资源;Host-PLV0模式下可以访问并控制处理器中除了用于调试功能外的所有其他资源;Guest-PLV0模式下只能访问部分处理器资源,如客户机控制状态寄存器;Host-PLV1/2/3和Guest-PLV1/2/3则只能访问更少的处理器资源。
图2.6 LoongArch各运行级别可访问并控制的处理器资源