计算机原理(二)

发布于:2025-09-07 ⋅ 阅读:(20) ⋅ 点赞:(0)

计算机原理系列

欢迎大家关注「海拉鲁知识大陆」 多交流不迷路

计算机原理(一)

继续上一篇计算机原理(一)深入了解程序执行部分,进一步说说程序在冯诺依曼模型上如何执行。如果没有了解的童鞋可以查看我上一篇文章。

1.程序的执行过程

当 CPU 执行程序的时候:
1.第一步,CPU 读取 PC 指针指向的指令,将它导入指令寄存器。完成读取指令这件事情有 3 个步骤:

  • 步骤 1:CPU 的控制单元操作地址总线指定需要访问的内存地址(简单理解,就是把 PC 指针中的值拷贝到地址总线中)。
  • 步骤 2:CPU 通知内存设备准备数据(内存设备准备好了,就通过数据总线将数据传送给 CPU)。
  • 步骤 3:CPU 收到内存传来的数据后,将这个数据存入指令寄存器。
    完成以上 3 步,CPU 成功读取了 PC 指针指向指令,存入了指令寄存器。

2.然后,CPU 分析指令寄存器中的指令,确定指令的类型和参数。
3.如果是计算类型的指令,那么就交给逻辑运算单元计算;如果是存储类型的指令,那么由控制单元执行。
4.PC 指针自增,并准备获取下一条指令。
图片

2.详解a=11+15的程序执行过程

上面我们了解了基本的程序执行过程,接下来我们来看看如果用冯诺依曼模型执行a=11+15是一个怎样的过程。

当我们写的程序a=11+15是字符串,CPU只能执行指令。所以这里需要用到编译器。编译器的核心能力是翻译,它把一种程序翻译成CPU可执行的语言。比如java语言就是把.java转换成.class文件类加载到JVM通过解释器和即时编译器(JIT Compiler)执行字节码指令(这里大概了解下,后面我会单独讲讲JVM工作原理)。
下面我们来详细阐述a=11+15的大体执行过程:

1.编译器通过分析,发现11和15是数据,因此编译好的程序启动时,会在内存中开辟出一个专门的区域存这样的常数,这个专门用来存储常数的区域,就是数据段,如下:

  • 11 被存储到了地址 0x100;
  • 15 被存储到了地址 0x104;
    图片

2.编译器将a=11+15转换成了 4 条指令,程序启动后,这些指令被导入了一个专门用来存储指令的区域,也就是正文段。如上图所示,这 4 条指令被存储到了 0x200-0x20c 的区域中:

  • 0x200位置的load指令将地址0x100中的数据11导入寄存器R0;
  • 0x204位置的load指令将地址0x104中的数据15导入寄存器R1;
  • 0x208位置的add指令将寄存器R0和R1中的值相加,存入寄存器R2;
  • 0x20c位置的store指令将寄存器R2中的值存回数据区域中的0x1108位置。

3.具体执行的时候,PC指针先指向0x200位置,然后依次执行这4条指令。

3.指令

在上面的例子中,load 指令将内存中的数据导入寄存器,我们写成了 16 进制:0x8c000100,拆分成二进制就大体如下:
图片

  • 最左边的6位,叫作操作码,英文是OpCode,100011代表load指令;
  • 中间的4位0000是寄存器的编号,这里代表寄存器R0;
  • 后面的22位代表要读取的地址,也就是0x100。

所以我们是把操作码、寄存器的编号、要读取的地址合并到了一个32位的指令中。
我们再来求加法运算的 add 指令,16进制表示是0x08048000,换算成二进制就是:
图片

  • 最左边的6位是指令编码,代表指令 add;
  • 紧接着的4位 0000 代表寄存器 R0;
  • 然后再接着的4位 0001 代表寄存器 R1;
  • 再接着的4位 0010 代表寄存器 R2;
  • 最后剩下的14位没有被使用。

构造指令的过程,叫作指令的编码,通常由编译器完成;解析指令的过程,叫作指令的解码,由CPU完成。由此可见CPU内部有一个循环:

  • 首先CPU通过PC指针读取对应内存地址的指令,单词就是Fetch 。
  • CPU对指令进行解码,单词就是Decode。
  • CPU执行指令,单词就是Execution。
  • CPU将结果存回寄存器或者将寄存器存入内存,单词就是Store。
    图片
    上面4个步骤,就是CPU的指令周期。CPU的工作就是一个周期接着一个周期,周而复始。

4.指令的类型

通过上面的例子,不同类型的指令、参数个数、每个参数的位宽,都不一样。而参数可以是以下这三种类型:

  • 寄存器;
  • 内存地址;
  • 数值(一般是整数和浮点)。

当然,无论是寄存器、内存地址还是数值,它们都是数字。
指令从功能角度来划分,大概有以下 5 类:

  • I/O 类型的指令,比如处理和内存间数据交换的指令 store/load 等;再比如将一个内存地址的数据转移到另一个内存地址的 mov
    指令。
  • 计算类型的指令,最多只能处理两个寄存器,比如加减乘除、位运算、比较大小等。
  • 跳转类型的指令,用处就是修改 PC 指针。比如编程中大家经常会遇到需要条件判断+跳转的逻辑,比如if-else,swtich-case、函数调用等。
  • 信号类型的指令,比如发送中断的指令 trap。
  • 闲置 CPU 的指令 nop,一般 CPU 都有这样一条指令,执行后 CPU 会空转一个周期。

指令还有一个分法,就是寻址模式,比如同样是求和指令,可能会有另个版本:

  • 将两个寄存器的值相加的 add 指令。
  • 将一个寄存器和一个整数相加的 addi 指令。
    另外,同样是加载内存中的数据到寄存器的 load 指令也有不同的寻址模式:
  • 比如直接加载一个内存地址中的数据到寄存器的指令la,叫作直接寻址。
  • 直接将一个数值导入寄存器的指令li,叫作寄存器寻址。
  • 将一个寄存器中的数值作为地址,然后再去加载这个地址中数据的指令lw,叫作间接寻址。

因此寻址模式是从指令如何获取数据的角度,对指令的一种分类,目的是给编写指令的人更多选择。

5.指令的执行速度

CPU其实是用石英晶体产生的脉冲转化为时钟信号驱动的,每一次时钟信号高低电平的转换就是一个周期,我们叫时钟周期。CPU的主频,说的就是时钟信号的频率。比如一个1GHz的CPU,说的是时钟信号的频率是1G。这就是我们买电脑熟悉的需要知道CPU的频率参数了,频率越高性能越好了。

这里再说明一下,不是每个时钟周期都可以执行一条指令。多数指令可能不在一个时钟周期完成,通常需要 2 个、4 个、6 个时钟周期。


网站公告

今日签到

点亮在社区的每一天
去签到