不以规矩.不能成方圆。--《孟子·离娄上》html
说到指令集以及CPU架构体系,你们就会想到计算机专业课程里面的计算机体系结构的方面的内容。既然课程中已经有了的内容我就不想那么枯燥的去复述一遍,而是先看一个类的定义:git
//定义寄存器编号
typedef enum : int {
Reg0,
Reg1,
Reg2,
Reg3
} RegNum;
//定义系统调用编号
typedef enum : int {
Int3 //设备输出,将寄存器Reg0中的内容输出到屏幕
} Interrupt;
//定义指令索引
typedef int Instruct;
/**
虚拟CPU类,模拟CPU所提供的指令。
虚拟CPU由4个寄存器和运算部件组成。四个寄存器的编号分别定义在RegNum中;运算部件提供了赋值、加减、比较、跳转9个指令。
*/
@interface VCPU : NSObject
//将一个常量值赋值给编号为reg的寄存器中。
-(void)moveFromConst:(int)val toReg:(RegNum)reg;
//将编号为reg1的寄存器中的值赋值给编号为reg2的寄存器中。
-(void)moveFromReg:(RegNum)reg1 toReg:(RegNum)reg2;
//将编号为reg的寄存器中的值赋值给地址为addr的内存中。
-(void)moveFromReg:(RegNum)reg toAddr:(Addr)addr;
//将地址为addr的内存中的值赋值给编号为reg的寄存器中。
-(void)moveFromAddr:(Addr)addr toReg:(RegNum)reg;
//将编号为reg1的寄存器中的值加上编号为reg2的寄存器中的值并将结果保存到编号为reg2的寄存器中。
-(void)addFromReg:(RegNum)reg1 toReg:(RegNum)reg2;
//将编号为reg1的寄存器中的值减去编号为reg2的寄存器中的值并将结果保存到编号为reg2的寄存器中。
-(void)subFromReg:(RegNum)reg1 toReg:(RegNum)reg2;
//若是两个寄存器内容相等则执行instruct所指定的指令,不然什么也不作。
-(void)isEqualReg:(RegNum)reg1 withReg:(RegNum)reg2 thenGoto:(Instruct)instruct;
//跳转到instruct所指定的指令中去。
-(void)jumpTo:(Instruct)instruct;
//系统返回
-(void)ret;
//系统调用,目前只支持屏幕输出调用Int3,表示将寄存器编号为0中的值输出到屏幕。
-(void)sys:(Interrupt)interrupt;
@end
复制代码
上面是一个叫VCPU的类的定义部分,它是一个用OC语言实现的用来模拟CPU功能的类。咱们再来看一个使用这个类的代码片断:github
-(void)main:(VCPU*)cpu memory:(VMemory*)memory
{
VINSTRUCT_BEGIN
VINSTRUCT(0, [cpu moveFromConst:10 toReg:Reg0]) //将常数10保存到CPU的寄存器Reg0中
VINSTRUCT(1, [cpu moveFromConst:15 toReg:Reg1]) //将常数15保存到CPU的寄存器Reg1中
VINSTRUCT(2, [cpu addFromReg:Reg0 toReg:Reg1]) //将寄存器Reg0中的值于寄存器Reg1中的值相加并保存到Reg1中
VINSTRUCT(3, [cpu moveFromReg:Reg1 toAddr:0x1000]) //将保存在Reg1中的相加结果保存到内存地址为0x1000处的内存中
VINSTRUCT(4, [cpu moveFromAddr:0x1000 toReg:Reg0]) //将内存地址0x1000处的内存值保存到寄存器Reg0中
VINSTRUCT(5, [cpu moveFromConst:25 toReg:Reg1]) //将常数25保存到CPU的寄存器Reg1中
VINSTRUCT(6, [cpu isEqualReg:Reg0 withReg:Reg1 thenGoto:9]) //若是Reg0中的值和Reg1中的值相等则执行第9条指令:进行打印输出
VINSTRUCT(7, [cpu moveFromReg:Reg1 toAddr:0x1000]) //将寄存器Reg1中的值保存到内存地址为0x1000中。
VINSTRUCT(8, [cpu jumpTo:10]) //跳转去执行第10条指令
VINSTRUCT(9, [cpu sys:Int3]) //系统调用,输出保存在Reg0中的值。
VINSTRUCT(10, [cpu ret]) //程序结束。
VINSTRUCT_END
}
复制代码
您能看懂上面代码所实现的功能吗(要想查看并运行完整的代码请到个人** github站点中的VirtualSystem**处下载)?您是否在例子里面隐约的感觉到了上面代码里面涉及到的一些关于CPU、内存、进程等方面的概念和知识了?它其实就是实现了以下的简单功能:objective-c
-(void)main
{
int a = 10;
int b = 15;
a = a + b;
if ( a == 25){
NSLog(@"output:%d",a);
}
}
复制代码
考察一下VCPU类,你会发现这个类提供了一些很是基础的操做方法:加减处理、数据移动、比较、地址跳转、系统调用等功能。调用者能够利用这个类提供的操做方法来编写并完成某个特定的功能。这个类的内部实现还提供了几个临时存储空间,能够经过RegNum编号来读写里面的数值。 VCPU其实是一个对真实CPU所具备的能力的一个简单的模拟类。咱们来看一下CPU的组成:编程
从上面的CPU结构图片中能够看出CPU主要分为存储单元(SU)和运算单元(ALU)以及控制单元(CU)。若是将这些部件和结构映射到VCPU这个类时你会发现:存储单元所对应的就是里面的数据成员;而运算单元和控制单元则对应里面的全部实例方法,运算单元提供了CPU指令的实现(VCPU类提供了众多的方法实现)。服务器
咱们称一个CPU里面所提供的全部的指令的集合称之为指令集。网络
咱们能够用OC语言来实现一个VCPU类,也能够用Swift语言来实现一个Swift版本的VCPU类,也能够用Java语言来实现一个Java版本的VCPU类。 这其中不一样的语言所提供的方法的定义形式是彻底不一样的: 就好比说OC里面能够提供直接操做内存地址的方法,可是Java里面则没法提供直接操做内存地址的方法;即便是OC语言中咱们要实现VCPU类中的方法也能够有不少种不一样的方式。架构
不一样的厂家以及不一样的技术工艺和技术水平以及具体的设备上所实现的CPU的体系架构以及提供的功能也是有差别的。好比ARM指令架构体系的CPU、x86指令体系架构的CPU、POWER-PC指令架构体系的CPU。这些不一样体系的CPU由于架构彻底不一样致使所提供的指令和存储单元也彻底不一样。咱们不可能让ARM指令直接在X86的CPU上执行(就如OC的提供方法没法在Java中执行是一个道理)。相同体系架构下的CPU指令则在必定程度上是能够相互兼容的,由于相同架构体系下的CPU的指令集是一致的(类比为接口一致,可是内部实现则不相同),好比说Intel公司所生产的x86系列的CPU和AMD公司所生产的x86系列CPU所提供的指令集是类似和兼容的,他们之间的差异只是内部的实现不一样而已。框架
CPU指令集定义的是一个中央处理器所应该提供的基础功能的集合,它是一个标准是一个接口也是一个协议。在软件开发中具备协议和接口定义的概念,不管是消费者仍是提供者都须要遵循这个标准来进行编程和交互:提供者要实现接口所具备的功能,至于如何实现则是内部的事情,不对外暴露,消费者也不须要知道具体的实现细节;消费者则老是要按接口提供的功能方法并组合使用来完成某种功能。这种设计的思惟对于硬件系统也是同样适用的。通常状况下某种CPU指令集一般都是由某些设计或者生产CPU的公司或者某标准组织共同定义而造成。那么目前市面上有哪些主流的CPU指令集或CPU架构体系呢?post
x86架构是Intel公司在1978年推出的Intel 8086中央处理器中首度出现,从Intel80386开始支持32位的系统。x86如今几乎是我的计算机的标准平台,成为了从来最成功的CPU架构。其余公司也有制造x86架构的处理器:有AMD、Cyrix、NEC、IBM、IDT以及Transmeta等。
64位架构
到2002年,因为32位特性的长度,x86的架构开始到达某些设计的极限。这个致使要处理大量的信息储存大于4GB会有困难。Intel本来已经决定在64位的时代彻底地舍弃x86兼容性,推出新的架构称为IA-64技术做为他的Itanium处理器产品线的基础。IA-64与x86的软件天生不兼容;它使用各类模拟形式来运行x86的软件,不过,以模拟方式来运行的效率十分低下,而且会影响其余程序的运行。AMD公司则主动把32位x86(或称为IA-32)扩充为64位。它以一个称为AMD64的架构出现(在重命名前也称为x86-64),且以这个技术为基础的第一个产品是单内核的Opteron和Athlon 64处理器家族。因为AMD的64位处理器产品线首先进入市场,且微软也不肯意为Intel和AMD开发两套不一样的64位操做系统,Intel也被迫采纳AMD64指令集且增长某些新的扩充到他们本身的产品,命名为EM64T架构(显然他们不想认可这些指令集是来自它的主要对手),EM64T后来被Intel正式改名为Intel 64(也就是x64指令集)。
在iOS编程时若是要运行在模拟器上,代码生成的机器指令时就须要指定使用i386仍是x64指令集,由于目前的mac电脑上基本采用了x86或者x64架构的CPU。
ARM处理器是英国Acorn有限公司设计的低功耗成本的第一款RISC微处理器。全称为Advanced RISC Machine。ARM处理器自己是32位设计,但也配备16位指令集。1978年12月5日,物理学家赫尔曼·豪泽(Hermann Hauser)和工程师Chris Curry,在英国剑桥创办了CPU公司(Cambridge Processing Unit),主要业务是为当地市场供应电子设备。1979年,CPU公司更名为Acorn公司。
起初,Acorn公司打算使用摩托罗拉公司的16位芯片,可是发现这种芯片太慢也太贵。"一台售价500英镑的机器,不可能使用价格100英镑的CPU!"他们转而向Intel公司索要80286芯片的设计资料,可是遭到拒绝,因而被迫自行研发。
1985年,Roger Wilson和Steve Furber设计了他们本身的第一代32位、6M Hz的处理器,
并用它作出了一台RISC指令集的计算机,简称ARM(Acorn RISC Machine)。这就是ARM这个名字的由来。
目前市面上的主流智能手机等移动设备配备的CPU都采用ARM架构。iOS应用真机编译出来的机器指令都是ARM指令,所以须要在编译时指定armv7或者arm64指令集。
此处参考自: baike.baidu.com/item/MIPS架构…
MIPS架构(英语:MIPS architecture,为Microprocessor without interlocked piped stages architecture的缩写),是一种采起精简指令集(RISC)的处理器架构,1981年出现,由MIPS科技公司开发并受权,普遍被使用在许多电子产品、网络设备、我的娱乐装置与商业装置上。最先的MIPS架构是32位,最新的版本已经变成64位。
目前国内的龙芯CPU,采用的就是MIPS指令集。
POWER-PC由摩托罗拉公司和苹果公司联合开发的高性能32位和64位RISC微处理器系列,以与垄断PC机市场的Intel微处理器和微软公司的软件相竞争。PowerPC微处理器1994年推出。
IBM之前跟Intel竞争过桌面处理器市场,但因为市场策略不当等缘由,IBM没赚到什么钱,因而决定退出桌面市场。POWER系列处理器是它退出桌面市场后才开发出来的服务器用处理器,苹果电脑用的处理器只是Power系列里的一种,听说是IBM为苹果特制的简化版本,而苹果独一无二的经营理念使苹果电脑与其它PC都不兼容,因此目前的Power系列处理器不能用于桌面PC。目前苹果电脑因PowerPC处理器不适合苹果发展而转而使用Intel处理器。
您是否在不少iOS库的头文件里面看到过POWER-PC的宏定义,早期的苹果电脑都用POWER-PC的CPU,如今苹果电脑基本都改成x64架构的CPU了。
上面列出了一些关于CPU架构和指令集的介绍,不一样的体系结构具备各自的优缺点,咱们能够从不一样的角度对CPU进行分类:
所谓字长就是指CPU的指令在一个周期内可以处理的最大的数字或者理解为对内存地址的最大的寻址能力。所以按这个长度能够作以下分类:
通常状况下大字长的CPU指令集都会兼容小字长的CPU指令集。好比32位的应用程序可以在64位的CPU上执行,而小字长的CPU指令集则没法直接提供大字长指令集的能力,如须要支撑则一般都是经过模拟来完成的,好比说一个64位字长CPU的读取数据指令在32位字长CPU上就能够经过模拟两次读取来完成,如今有的CPU提供了指令模拟的功能,所以某些64位的应用程序仍是能够运行在32位的CPU上的,只不过性能和速度会存在很大的损耗。
所谓指令的复杂度就是指CPU指令集中所提供的指令的数量、指令寻址模式、指令参数、以及CPU内部的架构设计的复杂度、以及指令自己所占据的字节数等来进行划分的一种方式,通常有两种类型的分类:
CISC指令集。CISC的英文全称为“Complex Instruction Set Computer”,即“复杂指令系统计算机”,从计算机诞生以来,人们一直沿用CISC指令集方式。早期的桌面软件是按CISC设计的,并一直沿续到如今。目前,桌面计算机流行的x86体系结构即便用CISC。在CISC微处理器中,程序的各条指令是按顺序串行执行的,每条指令中的各个操做也是按顺序串行执行的。顺序执行的优势是控制简单,但计算机各部分的利用率不高,执行速度慢。CISC架构的服务器主要以x86/x64架构(Intel Architecture)为主,并且多数为中低档服务器所采用。
RISC指令集。RISC的英文全称为“Reduced Instruction Set Computer”,即“精简指令集计算机”,是一种执行较少类型计算机指令的微处理器,起源于80年代的MIPS主机(即RISC机),RISC机中采用的微处理器统称RISC处理器。这样一来,它可以以更快的速度执行操做(每秒执行更多百万条指令,即MIPS)。目前的智能移动设备中的CPU几乎都采用RISC指令集,比较有表明的就是ARM指令集和POWER-PC指令集。
下面的表格举出了CISC和RISC两种体系结构的差异:
按指令流和数据流来进行分类的依据是CPU的一条指令能够同时处理多少条数据,或者一条数据同时被多少条指令处理,以及在一个CPU时间周期内能够同时执行多少条指令等规则来划分的。所以能够划分为以下四种:
单指令流单数据流机器(SISD) SISD机器是一种传统的串行计算机,它的硬件不支持任何形式的并行计算,全部的指令都是串行执行。而且在某个时钟周期内,CPU只能处理一个数据流。所以这种机器被称做单指令流单数据流机器。早期的计算机都是SISD机器,如冯诺.依曼架构,如IBM PC机,早期的巨型机和许多8位的家用机等。
单指令流多数据流机器(SIMD) SIMD是采用一个指令流处理多个数据流。这类机器在数字信号处理、图像处理、以及多媒体信息处理等领域很是有效。Intel处理器实现的MMXTM、SSE(Streaming SIMD Extensions)、SSE2及SSE3扩展指令集,都能在单个时钟周期内处理多个数据单元。也就是说咱们如今用的单核计算机基本上都属于SIMD机器。(我的以为GPU也属于这个范畴)
多指令流单数据流机器(MISD) MISD是采用多个指令流来处理单个数据流。因为实际状况中,采用多指令流处理多数据流才是更有效的方法,所以MISD只是做为理论模型出现,没有投入到实际应用之中。
多指令流多数据流机器(MIMD) MIMD机器能够同时执行多个指令流,这些指令流分别对不一样数据流进行操做。最新的多核计算平台就属于MIMD的范畴,例如Intel和AMD的双核处理器等都属于MIMD。
最后咱们仍是回到VCPU类来,VCPU是一个对CPU的简单的模拟实现。咱们知道用vmware软件能够用来模拟出一个操做系统运行的硬件环境,而实现了虚拟设备的功能;微软公司在2017年宣布他的Visual studio 2017上可以开发并运行iOS应用,而且能够无缝的将代码拷贝到XCODE上编译并运行。其实现的原理是Visual studio2017自己提供了一个OC语言编译器,同时他内部也提供了一个Cocoa UI框架的模拟实现版本,因此能在上面运行iOS应用。
从上面的几个例子中咱们能够发现一个特色就是:一个系统各个层次之间的调用老是经过某些约定的规则或者定义的接口来进行的,而且调用者是不知道也不须要知道提供者是如何实现这些能力的,老是一切皆是接口:
正是由于有这些接口的定义以及标准的造成,咱们才能够将本来真实的实现模拟出另一个虚拟的实现出来。这也就是所谓的虚拟化的本质。虚拟化能够发生在任何一个层面,也能够进行全局虚拟或者是部分虚拟。咱们能够对CPU的指令以及硬件接口进行模拟从而构建出一套相似vmware同样的虚拟机软件来运行任何操做系统;咱们也能够对操做系统提供的接口API进行模拟从而构建出一套相似Wine同样的虚拟Windows运行环境出来;咱们还能够对操做系统所提供的文件系统或者存储系统来进行模拟从而提供出一套相似Docker之类的应用容器出来;咱们也能够对Cocoa Framework进行模拟从而提供出一个套相似Vistual studio2017上能运行和编写OC应用的编译环境来(微软开源了这个框架:微软的OC实现支持)。
虚拟化首先要先接口标准定义,而后再在别人接口之上完成了一套本身的实现。如今的系统从上层的软件到下层的硬件之间都是经过接口协议进行调用的,所以咱们能够在各个层次上都实现虚拟的能力。
👉【返回目录】
欢迎你们访问个人github地址