CPU指令集:一串二进制指令表示执行某个功能

计算机的基本工作原理是什么?多知道一点没毛病

赛迪界面 2018-10-29 11:05:12

计算机的工作过程本质上就是执行程序的过程,而程序是由若干条指令组成的,计算机逐条执行程序中的指令,就可完成一个程序的执行,从而完成一项特定的工作。因此,要了解计算机的工作原理,就是要了解指令和指令执行的基本过程。

计算机的基本工作原理是什么?多知道一点没毛病

1.指令和程序

计算机之所以能脱离人的直接干预,自动地进行计算,是由于人把实现整个计算的一步步操作用命令的形式(即一条条指令)预先输入到存储器中,在执行时,机器把这些指令一条条地取出来,加以分析和执行。

通常一条指令对应着一种基本操作。一个计算机能执行什么样的指令,有多少条指令,这是由设计人员在设计计算机时决定的。计算机所能直接执行的全部指令,就是计算机的指令系统(Instruction Set)。

以二进制编码表示的指令叫机器指令,它通常包括操作码和操作数两大部分,操作码表示计算机执行什么操作,操作数指明参加操作的数的本身或操作数所在的地址。因为计算机只认识二进制数,所以计算机指令系统中的所有指令都必须以二进制编码的形式来表示。

计算机的基本工作原理是什么?多知道一点没毛病

程序即解题步骤。计算机的解题程序必须用计算机能识别的语言来描述,因此程序是指令的集合,用指令描述的解题步骤就叫程序。

2.指令的执行过程

按照冯·诺伊曼的存储程序思想,利用计算机解题首先要把指挥计算机如何进行操作的指令序列(即程序)和原始数据通过输入设备输送到计算机内存储器中,计算机运行时,依次从内存中取出一条条指令,控制器对指令进行分析判断,按照指令要求,发出不同的控制信号,在控制器的指挥下完成规定的操作,直到完成全部操作为止。所以,计算机的工作原理可以概括为存储程序和程序控制。

计算机的基本工作原理是什么?多知道一点没毛病

一般把计算机完成一条指令所花费的时间称为一个指令周期,指令周期越短,指令执行越快。通常所说的CPU主频或工作频率,就反映了指令执行周期的长短。

计算机在运行时,CPU从内存读出一条指令到CPU内执行,指令执行完,再从内存读出下一条指令到CPU内执行。CPU不断地取指令、分析指令、执行指令,这就是程序的执行过程。

总之,计算机的工作就是执行程序,即自动连续地执行一系列指令,而程序开发人员的工作就是设计程序。一条指令的功能虽然有限,但是由一系列指令组成的程序可完成复杂的任务。

程序员编写的代码为什么可以控制计算机硬件工作?

嵌入式时代 2018-10-27 22:49:52

计算机本质上是数字电路组成的计算机器,只有电信号才有可能驱动电路工作,那为什么程序员编写的代码可以控制计算机工作呢?代码只是一串字符而已。

程序员编写的代码为什么可以控制计算机硬件工作?

在回答这个问题前,先想一下,程序员编程时,是否要严格遵守某种编程语言的语法呢?答案是肯定的,每种高级语言,无论是C语言,还是java、python、php,都是有自己的关键字和语法结构的。这些关键字是设计编程语言时约定的,也就是说,程序员编写的代码是按照某种约定规则进行的。这就可以回答上面的问题了,假设一组数字电信号可以完成“蜂鸣”动作,既然它是数字信号,当然可以用数字表示它,下次程序员输入这组“数字”,就相当于输入了让计算机做“蜂鸣”动作的数字电信号,这就是机器码编程。

举个例子,假设有以下 5 盏灯。灯由开关控制着,只有开关两种状态。我们约定 1 表示开灯,0 表示关灯。那么,当电灯管理员得到“01000”这样一组数字时,他就知道了应该开第二盏灯,其他的关掉。

程序员编写的代码为什么可以控制计算机硬件工作?

机器码编程是不方便的,程序员想要完成某种计算功能,往往需要从非常庞大的指令表查找到相应的数字功能码。因此,后来人们设计了很多助记符,用有意义的单词来表示机器指令,这就形成了汇编语言。

就像上面的例子中,我们约定用 set_light_2 来表示 01000,那么,下次我告诉电灯管理员:“set_light_2”,他就明白了应该怎样开关灯。

顺着这样的思路,更复杂的符号和结构被设计成有意义的单词,高级语言如C语言,C++语言出现了。所以,说代码控制计算机不是特别恰当,因为代码只是我们约定的与电信号对应的符号而已。事实上,计算机并不能直接执行代码,代码要首先翻译为计算机认识的机器码(即数字信号序列),这一过程就叫做编译。

程序员编写的代码为什么可以控制计算机硬件工作?

当然,现在还有一些脚本语言,比如 python,它是依赖解释器逐行执行的。不过归根结底,代码要首先翻译为计算机认识的机器码(即数字信号序列)。

cpu的指令集为何具有差异性?你知道编译器很聪明,会优化代码吗

嵌入式时代 2018-10-29 09:26:52

上一节我们提到,编程语言里的各种符号都是与计算机底层数字电路的一种约定,这也是程序员编写的代码能够控制计算机工作的原因。对于设计架构好的计算机而言,以add命令为例,什么样的外在表现(比如产生一组数字电信号 0x83)能够使得计算机做一次 add 运算,我们就将什么外在表现定义为 add。

cpu的指令集为何具有差异性?你知道编译器很聪明,会优化代码吗

本例是约定 0x83 为 add 指令,之后,只要在输入设备输入 0x83 就能够产生的 add 指令对应的数字电信号序列,这样,计算机就可以执行 add 计算了。

所以,当计算机的架构改变后(例如cpu的电路设计改变),它的指令集通常也会变化(比如上面的add指令不是0x83了)。那么,同样一项业务,在不同架构的计算机上就得写不同的代码吗?这岂不是太麻烦了。的确,在机器码和汇编编程时代,这真的是个大问题,好在之后人们设计出了 C 语言,在一定程度上解决了这个问题:C语言代码具有可移植性,只需少量修改甚至不用修改,就能在不同架构上的计算机运行。

cpu的指令集为何具有差异性?你知道编译器很聪明,会优化代码吗

程序员们习惯称机器码和汇编语言为低级语言,C,c++等编程语言为高级语言。

C语言代码的可移植性能力其实归功于编译器,我们看下面这张图:

cpu的指令集为何具有差异性?你知道编译器很聪明,会优化代码吗

这是使用机器语言,汇编语言和C语言实现同一个功能的代码对比。因为汇编代码只是用较易记的符号代替机器语言的功能码,所以汇编代码和机器语言代码是一一对应的,从汇编语言代码到机器语言代码也只需简单替换即可。C语言代码就不一样了,它的一行语句,汇编语言需要使用3行来解释。上一节我们提到,计算机只能认识数字,所以C语言代码它是执行不了的,将 C 语言代码翻译为机器码是必须的。这里说的翻译,就是编译器的工作,编译器将高级语言代码翻译为计算机认识的机器码。

这就好理解为什么 C 语言能够较轻易的跨平台运行了:只要提供不同架构的计算机对应的编译器就可以了,编译器能够自动的将C语言代码翻译为指定架构的机器码。而一份编译器能够使用任意多次,所以这么做是非常划算的。

cpu的指令集为何具有差异性?你知道编译器很聪明,会优化代码吗

通过上面的例子,我们知道通常一行C语言代码,需要若干行机器码解释。一转多,就有很多可能性了,可能又N种转换方法能够完成工作,但是效率却可能大大不同。所以,编译器的优化对提升最终的运行效率而言非常关键。现在的编译器通常都优化的很好,请看下面这几句代码:

#include <stdio.h>

int main()

{

int a;

a = 1;

a = 2;

if(0==1)

a = 1+2;

return 0;

}

我们申请了一个 int 型的变量 a,然后分别赋值两次。但是对编译器而言,它可能会认为这几句代码什么也没做,因为你给 a 赋值,但是并没有使用 a 啊,所以它编译时,就认为你什么都没做,编译时,直接就将这两句忽略掉了。对于上面的 if 语句,因为 0 永远不可能等于 1,所以,编译器会认为这个 if 也是没有任何作用的,编译时,也就忽略它了。

我们编译它,然后查看编译后的汇编代码:

$ gcc -O2 t.c -g

$ objdump -dS a.out

a.out: file format elf64-x86-64

cpu的指令集为何具有差异性?你知道编译器很聪明,会优化代码吗

可以看出,最终生成的可执行文件,上面的代码实例中的 a 的两句赋值,和 if 判断被编译器判定没有意义,因此没有生成任何汇编代码。编译器认为没有的事情就不要做,以此提升效率。但是,在使用 C 语言操纵硬件,a 表示寄存器时,即使只是对 a 赋值也是非常有意义的,那编译器这么做不就出错了吗?事实的确如此,所以在 C99 标准中有 “volatile”关键字,就是专门解决这种问题的。下一节,我们再一起讨论一下“volatile”这个关键字。

cpu的指令集为何具有差异性?你知道编译器很聪明,会优化代码吗

欢迎在评论区一起讨论,质疑。文章都是手打原创,喜欢我的文章就关注一波吧。

本页共62段,3767个字符,10298 Byte(字节)