《操作系统真象还原》——0.25 指令集、体系结构、微架构、编程语言

简介: 假设我们的指令格式最大支持三个寄存器参数和一个立即数参数。其中操作码和各寄存器操作数各占1字节,立即数部分占4字节。各条指令并不是完全按照此格式填充,不同的指令有不同的参数,只有操作码部分是固定的,其他操作数部分是可选的。

本节书摘来自异步社区《操作系统真象还原》一书中的第0章,第0.25节,作者:郑钢著,更多章节内容可以访问云栖社区“异步社区”公众号查看

0.25 指令集、体系结构、微架构、编程语言

指令集是什么?表面上看它是一套指令的集合。集合的意思显而易见,那咱们说说什么是指令。

在计算机中,CPU只能识别0、1这两个数,甚至它都不知道数是什么,它只知道要么“是”,要么“不是”,恰好用0、1来表示这两种状态而已。

人发明的东西逃不出人的思维,所以,先看看我们人类的语言是怎么回事。

不同的语言对同一种事物有不同的名字,这个名字其实就是代码。比如说人类的好朋友:狗,咱们在中文里称之为狗,但在英文中它被称为dog,虽然用了两种语言,但其描述的都是这种会汪汪叫、对人类无比忠诚的动物。人是怎样识别小狗的呢?识别信息来自听觉、视觉等,这是因为人天生具备处理声音和图像的能力,能够识别出各种不同的声音和颜色不同的图像。可是计算机只能处理0、1这两个数,所以让计算机识别某个事物,只有用01这两个数来定义。也就是说,要用0、1来为各种事物编码。

为了更好地说明指令集,咱们这里不再用现有的语言举例子,当然也不是要自创指令集。下面举个简单的例子来演示指令集的模型。

咱们拿表达式A=B+C为例。假设A、B、C都是内存变量的值,它们的地址分别是0x3000、0x3004、0x3008。在此用Ra表示寄存器A,Rb表示寄存器B,Rc表示寄存器C。

完成这个加法的步骤是先将B和C载入到Ra和Rb寄存器中,再将两个寄存器的值相加后送入寄存器Ra,之后再将寄存器Ra的值写入到地址为0x3000的内存中。

步骤有了,咱们再设计完成这些步骤的指令。

步骤1:将内存中的数据载入到寄存器,咱们假设它的指令名为load。

screenshot

步骤2:两个寄存器的加法指令,假设指令名为add。

步骤3:将寄存器中的内容存储到内存,假设指令名为store。

以上指令名都是假设的,名字可以任意取,因为CPU不识别指令名。指令名是编译器用来给人看的,为的是方便人来编程,CPU它只认编码。目前CPU中的指令,无论是哪种指令集,都由操作码和操作数两部分组成(有些指令即使指令格式中没有列出操作数,也会有隐含的操作数)。咱们也采用这种操作码+操作数的思路,分别为这两部分编码。

咱们先为操作码设计编码。

screenshot

接下来为操作数编码,操作数一般是立即数、寄存器、内存等,咱们这里主要是为寄存器编码。
screenshot

好啦,操作码和操作数都有了,其实指令集已经完成了。不过在一长串的二进制01中,哪些是操作码,哪些是操作数呢?这就是指令格式的由来啦。我们人为规定个格式,规定操作码和操作数的大小及位置,然后在CPU硬件电路中写死这些规则,让CPU在硬件一级上识别这些格式,从而能识别出操作码和操作数。

假设我们的指令格式最大支持三个寄存器参数和一个立即数参数。其中操作码和各寄存器操作数各占1字节,立即数部分占4字节。各条指令并不是完全按照此格式填充,不同的指令有不同的参数,只有操作码部分是固定的,其他操作数部分是可选的。当CPU在译码阶段识别出操作码后,CPU自然知道该指令需要什么样的操作数,这是写死在硬件电路中的,所以不同的指令其机器码长度很可能不一致。

为了演示指令集模型,我们在上面假设了寄存器名、指令名、格式。按理说这对于指令集来说已经全了,不过,为方便咱们了解编译器,不如咱们再假设个指令的语法吧,咱们这里学习Intel的语法格式:“指令目的操作数,源操作数”。目的操作数在左,源操作数在右,此赋值顺序比较直观。Intel想表达的是 a=b这种语序,如a=b,便是mov a,b。

以上三个步骤的机器码按照十六进制表示为:
screenshot

以上自定义的指令便是按照咱们假设的语法来生成的。对于机器码的大小,由于指令不同,需要的操作数也不同,所以机器码大小也不同。另外,机器码中的立即数是按照x86架构的小端字节序写的,这一点大家要注意。小端字节序是数值中的低位在低地址,高位在高地址,数位以字节为单位。前面有一小节说明大小端字节序问题。

步骤2的机器码为01 00 01 10。操作码占1字节,CPU识别出第1字节的二进制01是add指令,知道此指令的操作数是3个寄存器,并且第1个寄存器操作数是目的寄存器,另外两个寄存器是源操作数(这都是我们假定的,并且是写死在硬件中的规则,不同的指令有不同的规则,您也可以创造出内存和寄存器混合作为操作数的加法指令)。于是到第2字节去读取寄存器编码,发现其值为二进制00,就是寄存器Ra对应的编码。接着到下一个字节处继续读出寄存器编码,发现是二进制01,也就是寄存器Rb,Rc同理。于是将寄存器Rb和Rc的值相加后存入到寄存器Ra。

步骤3中,机器码为10 00 0c300000,CPU读取机器码的第1 字节发现其为二进制10,知道其为指令store,于是便确定了,目的操作数是个立即数形式的内存地址,源操作数是个寄存器。接着到指令格式中的寄存器操作数1的位置去读取寄存器编码,发现其值为00,这就是寄存器Ra的编码。机器码中剩下的部分便作为立即数,这样便将寄存器Ra的值写入到内存0x0000300c中了。

以上指令集的模型,确实太过于简单了,也许称之为模型都非常勉强。现实中的指令格式要远远复杂得多。下面我们看看目前世面上的指令集有哪些。

最早的指令集是CISC(Complex Instruction Set Computer),意为复杂指令集计算机。从名字上看,这套指令集相当复杂,当初这套指令集问世的时候,它的研发者们都没想过要给它起名,只是因为后来出现了相对精简高效的指令集,所以人们为了加以区分,才将最初的这套相对复杂的指令集命名为CISC,而后来精简高效的指令集称为RISC(Reduced Instruction Set Computer)。

CISC和RISC并不是具体的指令集,而是两种不同的指令体系,相当于指令集中的门派,是指令的设计思想。举个例子,就像中医与西医,中医讲究从整体上调理身体,西医则更多的是偏向局部。这就是两种不同的医疗思路,类似于CISC和RISC这两种指令体系。那什么是指令集呢?拿中医举例,像华佗、张仲景这两位医圣,他们虽然都是基于中医的思想治病,但医术各有特色,水平也不尽相同,这就相当于不同的指令集。一会儿咱们会介绍具体的指令集。

为什么说CISC复杂呢?

首先,因为它是最早的指令集,当初都是摸着石头过河,肯定有一些瑕疵在里面。其次,当初的程序员都是用汇编语言开发程序,他们当然希望汇编语言强大啦,尽量多一些指令,尽量一个指令能多干几件事,所以指令集中的指令越来越多,越来越复杂。不过这样的好处是程序员同学很爽。最后,CISC是Intel使用的指令集,Intel公司在兼容性方面做得最好,指令集在发展的过程中,还要兼容过去有瑕疵的古董,以至于最后的指令集变得有点“奇形怪状”了。

作为后起之秀的RISC,借鉴了前辈CISC的经验,取其精华,弃其糟粕,当然要更好更轻量啦。它是怎么来的呢?

CISC不是做得很全很强吗,可是很多时候,程序员并不会用到那些复杂的指令和寻址方式,即使用到了,编译器有时候为了优化,未必“全”将其编译为复杂的形式。这就导致了CPU中的复杂的指令和寻址方式无用武之地。根据二八定律,指令集中20%的简单指令占了程序的80%,而指令集中80%的复杂指令占了程序的20%。根据这个特性,处理器及指令集被重新设计,保留了那些基本常用的指令,减少了硬件电路的复杂性。这样,大部分指令都能在一个时钟周期内完成,更有利于提升流水线的效率。而且,指令采用了定长编码,这样译码工作更容易了。由于其太优秀了,后来的处理器,如MIPS,ARM,Power都采用RISC指令体系,做得最好的就是MIPS处理器,它严格遵守RISC思想,业界公认其优雅。

我们常用的CPU是Intel和AMD公司的产品,它们用的指令集便是基于CISC思想的x86。AMD的x86指令架构是Intel授权给他们的,为区别于此,Intel在官方手册上称自己的指令集为IA32。

虽然AMD采用的也是x86指令集,但Intel可没把硬件实现方法也告诉AMD,否则AMD的CPU和Intel的CPU不就完全一样了吗,人家Intel也不肯呢。指令集是一套约定,里面规定的是有哪些指令、指令的二进制编码、指令格式等,如何实现这套约定,这是硬件自己的事。打个比方,这就像和朋友约好了在某餐厅吃饭,咱是坐车去,还是走着去,这是咱们的事,与吃饭是无关的。说白了,在Intel的CPU上运行的软件也能够在AMD的CPU上运行,原因就是它们共用了同用一套指令集,也就是对二进制编码达成了共识。它们面对相同的需求,可能采取了不同的行动,但都完成了任务。比如机器码是b80000,Intel的CPU经过译码,知道这是将0赋值给寄存器ax,相当于汇编语言mov ax,0。AMD的CPU在译码时,也得将此机器码认为是将0赋值给寄存器ax。至于它们在物理上是怎么将0传入寄存器ax中的,这是它们各自实现的方式,与指令集无关。它们各自实现的方式,就叫微架构。

总结一下,指令集是具体的一套指令编码,微架构是指令集的物理实现方式。

发展到后来,x86指令集越来越复杂。它本属于CISC体系,但由于效率低下,最终在其内部实现上采取了RISC内核,即一条CISC指令在译码时,分解成多条RISC指令,这样其执行效率便可与RISC媲美啦。

目前市面上常见的指令集有五种,除x86是CISC指令体系外,ARM、MIPS、Power、C6000都是RISC指令体系的指令集。

CPU与指令集是对应的,一种CPU只能识别一种指令集,所以很多CPU都以其支持的指令集来称呼。比如ARM、MIPS,它们本身是CPU名称,又是指令集名称。

ARM主要用在手机中,作为手机的处理器。Power是IBM用于服务器上的处理器。C6000是数字信号处理器,广泛用于视频处理。而MIPS虽然本身很优秀,但其在各领域起步都较晚,并没有广泛应用的领域。

由于MIPS本身的优越性,龙芯用的就是mips指令集,有没有人问,为什么咱们自主研发的CPU还要用人家国外的指令集?就不能也研发出一套指令集吗?能倒是能,不过语言不通用。就像我自己可以发明一门语言,语言本身没什么问题,问题是我用自己发明的语言和别人交流,谁听得懂呢,谁又愿意去学这门语言呢?大家都很忙,不通用的东西没人愿意花精力去学。如果龙芯也自立门户创造新的指令集,那有谁愿意给它写编译器呢?即使有了编译器,操作系统也要重新编译发布,应用程序也要重新编译发布,指令集背后不仅是个计算机生态链,更重要的是全球经济链。

平时所说的编程语言,虽然其上层表现各异,归根结底是要在具体的CPU上运行的,所以必须由编译器按照该CPU的指令集,翻译成符合该CPU的指令。说到这,不得不说一下交叉编译,本质上交叉编译就是用在A平台上运行的编译器,编译出符合B平台CPU指令集的程序,编译出的程序直接能在B平台上运行啦。这里的平台指的就是CPU指令体系结构。

相关文章
|
5天前
|
Android开发 Swift iOS开发
深入探索iOS与Android操作系统的架构差异及其对应用开发的影响
在当今数字化时代,移动设备已经成为我们日常生活和工作不可或缺的一部分。其中,iOS和Android作为全球最流行的两大移动操作系统,各自拥有独特的系统架构和设计理念。本文将深入探讨iOS与Android的系统架构差异,并分析这些差异如何影响应用开发者的开发策略和用户体验设计。通过对两者的比较,我们可以更好地理解它们各自的优势和局限性,从而为开发者提供有价值的见解,帮助他们在这两个平台上开发出更高效、更符合用户需求的应用。
|
1月前
|
存储 安全 物联网
操作系统的心脏:深入理解现代操作系统架构与核心技术
本文旨在为读者提供一个关于现代操作系统(OS)架构和核心技术的全面概述。通过分析OS的主要组件、功能以及它们如何协同工作,本文揭示了操作系统在计算机系统中的核心地位及其复杂性。我们将探讨进程管理、内存管理、文件系统和输入/输出(I/O)等关键技术,并讨论它们对系统性能的影响。此外,本文还将涵盖一些最新的操作系统趋势和技术,如云计算、虚拟化和物联网(IoT)。通过阅读本文,读者将获得对操作系统内部运作方式的深刻理解,这对于软件开发人员、IT专业人士以及对计算机科学感兴趣的任何人来说都是宝贵的知识。
|
1月前
|
安全 调度 开发者
探索操作系统的心脏:现代内核架构与挑战
【10月更文挑战第7天】 本文深入探讨了现代操作系统内核的复杂性和功能性,从微观角度剖析了内核在系统运行中的核心作用及其面临的主要技术挑战。通过浅显易懂的语言解释专业概念,旨在为读者提供一个关于操作系统内核的全面视角。
38 2
|
1月前
|
存储 人工智能 物联网
探索现代操作系统的架构与演进
【10月更文挑战第5天】 本文旨在深入探讨现代操作系统的核心架构及其在技术演进中的变革。通过对操作系统的基本概念、关键组成部分以及它们如何相互协作的分析,为读者提供一个全面且易于理解的视角。同时,本文还将回顾操作系统从单任务到多任务、从单用户到多用户的发展过程,并展望未来可能的技术趋势。
|
6天前
|
缓存 运维 网络协议
深入Linux内核架构:操作系统的核心奥秘
深入Linux内核架构:操作系统的核心奥秘
22 2
|
28天前
|
存储 资源调度 算法
操作系统的心脏:深入理解内核架构与机制####
【10月更文挑战第16天】 本文旨在揭开操作系统最神秘的面纱——内核,通过剖析其架构设计与关键机制,引领读者一窥究竟。在这篇探索之旅中,我们将深入浅出地讨论内核的基本构成、进程管理的智慧、内存分配的策略,以及那至关重要的系统调用接口,揭示它们是如何协同工作,支撑起现代计算机系统的高效运行。这既是一次技术的深潜,也是对“看不见的手”调控数字世界的深刻理解。 ####
40 3
|
1月前
|
存储 算法 安全
操作系统的心脏:深入理解现代操作系统架构与调度机制
本文将探讨现代操作系统的核心概念,包括进程管理、内存管理和 I/O 系统。通过分析这些组件如何协作以提供稳定和高效的计算环境,帮助读者更好地理解操作系统在现代计算中的重要性。我们将从宏观角度出发,逐步深入到微观细节,为读者提供全面而详细的技术解析。
|
1月前
|
安全 调度 虚拟化
探索现代操作系统的架构与优化
本文将深入探讨现代操作系统的核心架构和优化技术。从操作系统的基本定义入手,逐步解析其内核结构、进程管理、内存管理和I/O系统。同时,还将讨论现代操作系统在多核处理器支持、虚拟化技术和安全性方面的创新与优化措施。通过这些内容,读者可以全面了解操作系统的工作原理及其在实际应用中的表现与改进。
|
1月前
|
存储 算法 Linux
探索现代操作系统的架构与优化
本文深入探讨了现代操作系统的核心架构及其性能优化策略。通过对主流操作系统架构的分析,揭示其在多任务处理、内存管理和文件系统等方面的特点。同时,针对当前技术趋势,提出一系列优化措施,旨在提升系统的运行效率和用户体验。通过实例分析,展示如何在实际场景中应用这些优化技术,确保系统在高负载下的稳定运行。
|
1月前
|
存储 安全 数据安全/隐私保护
探究现代操作系统的架构与优化策略
本文旨在深入探讨现代操作系统的核心架构及其性能优化方法。通过分析操作系统的基本组成、关键技术和面临的挑战,揭示如何通过技术手段提升系统效率和用户体验。不同于传统的技术文章摘要,这里不罗列具体研究方法和结果,而是以简明扼要的语言概述文章的核心内容和思考方向,为读者提供宏观视角和技术深度。 生成
28 3

热门文章

最新文章