计算机指令的入门


计算机指令的入门

上个实际可没有什么C语言、Java语言等高级语言。那之前的程序员是如何编程的?
答案:打孔卡(Punched Card)我在下面贴了一张图
在这里插入图片描述
那个时候,人们在特定的位置上打洞或者不打 洞,来代表“0”或者“1”,即使在今天,我们使 用的现代个人计算机,仍然只能处理所谓的“机器码”,也就是一连串的“0”和“1”这样的数字。
我在这里提出两个问题:

  1. 高级语言的程序,最终是怎么变成一串串“0”和“1”的?
  2. “0”和“1”又是 怎么在CPU中处理的?

在硬件方面,CPU干了啥?

CPU的全称是Central Processing Unit,中文是中央处理器。从硬件的角度来看,CPU就是一个超大规模集成电路,通过电路实现了加法、乘法乃至各 种各样的处理逻辑。从软软件件工程师的角度来讲,CPU就是一个执行各种计算机指令(Instruction Code)的逻辑机器。

不同的CPU支持的语言不同,也就是支持指令集不同。

存储程序型计算机:一个计算机程序,不可能只有一条指令,而是由成千上万条指令组成的。但是CPU里不能一直放着所有指 令,所以计算机程序平时是存储在存储器中的。当然也有不是存储程序型计算机了。

代码如何变成机器码

代码----编译----汇编代码—翻译—机器码
如果我们使用的是C语言,在一个Linux操作系统上,我们可以简单地使用gcc和objdump这样两条命令,把对应的汇编代码和机器码都 打印出来。
下面的例子是COPY来的。

1
2
3
4
5
6
// test.c
int main()
{ int a = 1;
 int b = 2;
 a = a + b;
 }

下面是编译和翻译过来的
在这里插入图片描述
可以查看每个机器码对应每个汇编代码,这就是为什么开发人员知道汇编语言,就可以了解机器码的执行过程了。

指令和机器码

我们 日常用的Intel CPU,有2000条左右的CPU指令,实在是太多了,不过一般来 说,常见的指令可以分成五大类。

第一类是算算术术类类指指令令。我们的加减乘除,在CPU层面,都会变成一条条算术类指令。
第二类是数数据据传传输输类类指指令令。给变量赋值、在内存里读写数据,用的都是数据传输类指令。
第三类是逻逻辑辑类类指指令令。逻辑上的与或非,都是这一类指令。
第四类是条条件件分分支支类类指指令令。日常我们写的“if/else”,其实都是条件分支类指令。
最后一类是无无条条件件跳跳转转指指令令。写一些大一点的程序,我们常常需要写一些函数或者方法。在调用函数的时 候,其实就是发起了一个无条件跳转指令

在这里插入图片描述
我们选用最简单的MIPS指令集,来看看机器码是如何生成的。
MIPS是一组由MIPS技术公司在80年代中期设计出来的CPU指令集。就在最近,MIPS公司把整个指令集和芯 片架构都完全开源了。
在这里插入图片描述
MIPS的指令是一个32位的整数,高6位叫操操作作码码(Opcode),也就是代表这条指令具体是一条什么样的指 令,剩下的26位有三种格式,分别是R、I和J。

  • R指令是一般用来做算术和逻辑操作,里面有读取和写入数据的寄存器的地址。如果是逻辑位移操作,后面 还有位移操作的位移量,而最后的功能码,则是在前面的操作码不够的时候,扩展操作码表示对应的具体指 令的。
  • I指令,则通常是用在数据传输、条件分支,以及在运算的时候使用的并非变量还是常数的时候。这个时 候,没有了位移量和操作码,也没有了第三个寄存器,而是把这三部分直接合并成了一个地址值或者一个常 数。
  • J指令就是一个跳转指令,高6位之外的26位都是一个跳转后的地址。

我以一个简单的加法算术指令add $t0, $s1, $s2,为例,给你解释。为了方便,我们下面都用十进制来表示对 应的代码。 对应的MIPS指令里opcode是0,rs代表第一个寄存器s1的地址是17,rt代表第二个寄存器s2的地址是18,rd 代表目标的临时寄存器t0的地址,是8。因为不是位移操作,所以位移量是0。把这些数字拼在一起,就变成 了一个MIPS的加法指令。 为了读起来方便,我们一般把对应的二进制数,用16进制表示出来。在这里,也就是0X02324020。这个数 字也就是这条指令对应的机器码。
在这里插入图片描述
哈哈假如你要使用打孔卡,你该如何办?你去思考下。