5. 计算机指令是如何被执行的?

1. 最早的数据存储介质——打孔卡与纸带

上图是上世纪60年代晚期或70年代初期,Arnold Reinold拍摄的FORTRAN计算程序的穿孔卡照片
IBM早在1928年就推出了规格为190x84mm的打孔卡(Punched Card),用长方形孔提高存储密度,通常可以存储80列x12行数据,相当于120字节。后来做成了穿孔纸带。
在这里插入图片描述
打孔卡与穿孔纸带在很长一段时间内共存,是机械化存储技术时代的标志。
这种存储介质我们一直在使用。
2001年,我使用的金龙卡,也就是校园饭卡
目前还在使用的大学英语四六级答题卡CET-4/CET-6
“0”:表示光没有通过;“1”表示光通过了。为什么早期的计算机会采用打孔卡这样的存储设备,而不用像C或者Python这样的高级计算机语言编写呢?因为早期的计算机或者CPU没有理解这些高级语言的能力。但是,即便是2021年的今天,计算机也只能计算由“0”和“1”组成的二进制,即“机器码”或机器语言(Machine Language),只是计算机对人而言更友好了,它们会自动“翻译”(更准确都说是“编译”)不同的语言。计算机用二进制语言,人用高级计算机语言(例如:英语)。

2. 在计算机指令执行中,CPU做了什么?

CPU(Central Processing Unit)从硬件工程师的角度看,是一个超大规模集成电路(Very Large Scale Integrated Circuit,简写VLSI)。但从软件工程师德角度看,CPU是一个执行各种计算机指令(Intruction),能听懂各种计算机语言,进行计算的设备。但是,不同的CPU能够听懂的计算机语言不太一样,专业术语叫做不同架构的CPU。主要有:
1)以Intel、AMD公司为代表的X86架构的CPU,用的是复杂指令集(Complex Instruction Set Computer,简写CISC),主要用途为个人电脑(Personal Computer,简写PC)、服务器。
2)以Apple、ARM公司为代表的ARM架构的CPU,用的是精简指令集(Reduced Instruction Set Computer,简写RISC),主要用途为各种手机、苹果电脑。
3)以IBM公司为代表的PowerPC架构的CPU,用的也是简指令集(Reduced Instruction Set Computer,简写RISC),主要用途为中高端的嵌入式系统中。

可见PC机上编写的程序不能通过复制到手机上运行,就是因为不同架构的CPU支持的**计算机指令集(Instruction Set)**是不同的。

计算机程序不可能只有一条指令,而是由成千上万的指令组成的。CPU 中不可能一直存放着所有指令,所以计算机程序平时是存储在存储器中的。这种程序指令存储在存储器里面的计算机,就叫作存储程序型计算机(Stored-program Computer)

其实,早前还有一种存储程序型计算机,就做“插线板计算机”(Plugboard Computer)
IBM的Plugboard计算机

3. 计算机高级语言是如何变成机器码的呢?

以一段C语言程序为例

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

如何让这个程序在Linux操作系统 or Windows操作系统 上运行起来呢?

答:需要将C语言翻译成一个汇编语言(Assembly Language,简写ASM),这个过程称为编译(Compile),再由汇编器(Assembler)翻译为机器码。这些由“0”和“1”组成的机器码就是一条条计算机的指令。为了阅读方便(否则太长),用16进制来表示机器码。
在这里插入图片描述
在Linux操作系统上,使用gcc和objdump命令将汇编语言和机器码打印出来。

$ gcc -g -c test.c
$ objdump -d -M intel -S test.o

一条C语言指令可以对应一条汇编语言指令,也可以对应多条(2条以上,含2条)汇编语言指令。汇编语言指令与机器码则是一一对应的。

test.o:     file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <main>:
int main()
{
   0:   55                      push   rbp
   1:   48 89 e5                mov    rbp,rsp
  int a = 1; 
   4:   c7 45 fc 01 00 00 00    mov    DWORD PTR [rbp-0x4],0x1
  int b = 2;
   b:   c7 45 f8 02 00 00 00    mov    DWORD PTR [rbp-0x8],0x2
  a = a + b;
  12:   8b 45 f8                mov    eax,DWORD PTR [rbp-0x8]
  15:   01 45 fc                add    DWORD PTR [rbp-0x4],eax
}
  18:   5d                      pop    rbp
  19:   c3                      ret    

汇编语言是给“程序员看的机器码”。

问:在Windows操作系统上,是如何实现的呢?

4. 汇编指令和机器指令的解析

指令可以分为大类:
1)算术指令:加减乘除。
2)数据传输指令:给变量赋值,在内存里读写数据。
3)逻辑指令:与、或、非、异或。
4)条件分支指令:if…else…,for,while。
5)无条件跳转指令:函数(function)调用,方法(method)调用,goto。
在这里插入图片描述
不同的CPU的指令集是不同的,例如Intel的CPU的指令集有2000多条指令。这里选用最简单的MIPS指令集来学习。MIPS指令集是MIPS公司在二十世纪80年代设计的CPU指令集,现在已经开源了,可以点击MIPS官网这里获得。国产龙芯2E微处理器是一款实现64位MIPSⅢ指令集的通用RISC处理器。
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

MPIS指令集是32位(bit)的指令。
1)高6位是操作码(Operational Code,即OP code),可以理解为具体的动词,CPU具体的操作指令/行为。剩余的26位有R、I、J三种格式。
2)R指令:用来做算术和逻辑操作,里面有读取和写入数据的寄存器的地址。如果是逻辑位移操作,后面还有位移操作的位移量。而最后的功能码,则是在前面的操作码不够的时候,扩展操作码表示对应的具体指令。
3)I指令:用在数据传输、条件分支,以及在运算的时候使用的并非变量而是常数的时候。这个时候,没有了位移量和操作码,也没有了第三个寄存器,而是把这三部分直接合并成了一个地址值或者一个常数。
4)J指令:跳转指令,高 6 位之外的 26 位都是一个跳转后的地址。

例如

add $t0,$s1,$s2  #将寄存器t0中的内容变为寄存器S1和寄存器S2中内容的和

在这里插入图片描述
1)操作码:汇编指令【add】,机器指令【opcode中的0】。
2)rs,第一个源操作数(OP num):汇编指令【 s 1 】 , 机 器 指 令 【 17 】 , 表 示 寄 存 器 s 1 的 地 址 为 17 ( 这 里 用 10 进 制 表 示 了 ) 。 3 ) r t , 第 二 个 源 操 作 数 : 汇 编 指 令 【 s1】,机器指令【17】,表示寄存器s1的地址为17(这里用10进制表示了)。 3)rt,第二个源操作数:汇编指令【 s117s117103rts2】,机器指令【18】,表示寄存器s2的地址为18(如果用16进制表示未0x12)。
4)rd,目标寄存器:汇编指令【$t0】,机器指令【8】,表示目标寄存器t0的地址为8。
5)因为不是移位操作,所以偏移量shamt为0。
6)功能码或函数码为0x20。
如果用打孔卡实现为:
在这里插入图片描述
这里我们用的C语言,C语言是一种编译型计算机语言。可以用Python语言实现,Python是一种解释型计算机语言。还可以用Java语言实现,Java语言是一种使用虚拟机的语言。

  • 7
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

叶老师讲大数据

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值