一、先导问题
- 程序是什么?
指令的集合
- 程序由什么组成?
指令和数据
- 什么是机器语言?
CPU可以直接识别并解释执行的语言
- 正在运行的程序存储在什么位置?
内存
- 什么时内存地址?
用于表示内存中存储指令与数据的存储位置的数值
- 计算机构成元件中,负责程序的解释和运行的是哪个?
CPU
二、主要内容
【一】 CPU内部结构
- 寄存器(重点)
(1)暂存由内存复制过来的指令与数据等处理对象,可以看成内存的一种。
(2)种类多样,每一种有不同的用途,下小节会介绍。
- 控制器
(1)负责把内存上的数据与指令等处理对象读入寄存器。
(2)根据指令的执行结果控制整个计算机。
(3)”控制“表示除数据运算以外的处理,主要为输入输出的时机控制,如内存硬盘的读写,鼠标键盘的输入,显示器打印机的输出等。
- 运算器
(1)运算寄存器中的数据,寄存器的数据来自于内存。
- 时钟
(1)向CPU发送时钟计时信号
对内存的简单解释
(1)内存通常来说指计算机的主存储器,简称主存。通过控制芯片等与CPU相连,主要负责存储数据与指令,由可读写元素构成,每个字节都带有地址编号。CPU通过该地址读取数据与指令到寄存器,或者写入数据至内存。
(2)主存中存储的指令与数据会根据计算机的关机而删除(DRAM)。DRAM:动态随机存取存储器,RAM可进行读写,速度快,非长久保存
ROM:只读存储器,可永久保存,断电不会刷新数据,类似硬盘技术
程序运行机制的简单解释
- 使用高级编程语言编写程序
- 程序编译成为机器语言的exe文件,保存在硬盘中
编译:使用编译器,将高级语言转换成为机器语言的过程
汇编:使用汇编器,将汇编语言(低级语言)转换为机器语言的过程
- 程序运行时,内存中生成exe文件副本
- CPU通过控制器将指令与数据暂存至寄存器
- 控制器执行寄存器中的指令
- 运算器根据控制器的控制,计算寄存器中的数据
- 控制器根据运算器的结果进一步控制计算机
【二】 CPU是寄存器的集合体
程序是将寄存器当作对象来描述的。
(1)内存的存储场所通过地址区分,寄存器种类通过名字区分
(2)汇编中直接通过寄存器名字操作寄存器以及其中的数据,将寄存器视为一个可操作对象,而不再对其进行拆分。
寄存器种类
由于“数据”可分为:1.表示内存地址的数值 2.表示用于运算的数值,因此存储数据和指令的寄存器也分为不同种类。
【三】 决定程序流程的程序计数器
通过程序流程直观感受程序计数器对于程序运行的控制:
以顺序执行的程序为例(不含函数调用与分支循环)
- 用户发出运行程序的指令
- 操作系统将保存在硬盘中的程序复制到内存中
- 内存通过地址划分存储区域,假设程序在内存中起始地址
0100
- 操作系统将程序复制到内存后,将程序计数器(CPU寄存器的一种)设定为程序的起始地址
0100
- CPU控制器根据程序计数器保存的数据,找到内存
0100
地址中的指令进行执行 - 控制器执行这一指令后,程序计数器加一,指向内存地址
0101
,即程序在内存中的下一指令。加一操作是默认所执行的指令占用了一个内存地址,若指令占用了n个内存地址,则程序计数器增加n - 控制器不断执行程序计数器所指向的指令,程序计数器不断变化,最终执行完程序
【四】 条件分支与循环机制
1.顺序执行:按照地址内容顺序执行指令
2.条件分支:按照条件执行任意特性地址的指令
3.循环执行:重复执行某一地址或某些地址的指令
以条件分支为例:0102
指令为jump
(跳转)指令,跳转0104
- 程序起始位置
0100
,程序计数器设定0100
,控制器执行0100
指令 0100
执行完毕,程序计数器加1,控制器执行0101
指令0101
执行完毕,程序计数器加1,控制器执行0102
指令,0102
指令通过标志寄存器进行条件判断,假设满足跳转条件,jump
指令跳转至0104
,间接执行将程序计数器设定为0104
的操作- 控制器执行
0104
标志寄存器:保存累加寄存器的结果状态(正零负),同样保存溢出与奇偶校验的结果。
(1)溢出:验证运算结果是否超出寄存器长度范围
(2)奇偶校验:验证运算结果的值是奇数还是偶数
(3)正零负:32位寄存器(0-31)的后三位(0、1、2)为1时分别表示运算结果为正数、零、复数CPU比较机制:例:累加寄存器中XXX与通用寄存器YYY进行比较:
(1)CPU内部(暗中)将XXX与YYY进行减法运算
(2)将XXX-YYY结果保存到标志寄存器中,标志寄存器为正则XXX大,为负则YYY大,为0则二者相等。
【五】函数的调用机制
函数调用机制与条件分支、循环机制的不同: 即为什么函数调用无法使用
jump
指令进行跳转。以函数调用流程举例,因为一行代码往往对应多条指令,所以一行代码所直接对应的地址是离散的,例如程序起始位置的第一行代码对应地址
0100
,而第二行代码对应的地址是0123
而不是0101
,不过为了演示方便我还是按一个地址对应一行代码进行演示:
(1)程序起始位置0100
,与控制器配合,执行到0102
处
(2)此时程序计数器内数据为0102
,对应指令为函数调用,使用jump
指令跳转至函数入口0145
,执行代码体内容
(3)函数执行完毕,此时程序计数器指向函数末尾地址0155
,期望结果是程序计数器设定为调用函数指令0102
的下一条指令0103
, 但是实际上,jump
命令无法做到这一点。为什么
jump
指令可以做到分支循环的回溯,而无法做到函数的返回呢?(1)在条件分支或循环中,程序可由
0102
跳转至0104
,也可由0108
(循环体末尾)跳转回0102
,因为0102
指令指明了跳转的地址为0104
,当循环体执行完毕后,0108
地址同样指明了跳转回0102
。
(2)在函数调用中,0102
调用函数,进入函数入口0145
,执行完函数体后,0155
指令并没有指明返回的地址为0103
,因此无法完成跳转。
因此需要设计一组指令,完成函数跳转与函数返回,这个过程
call与return
(1)call:在函数入口设定到程序计数器之前,将函数调用指令的下一条指令地址放入名为栈的主存中。
(2)return:当函数体执行完毕后,将栈中的后续地址设定到程序计数器中,完成函数的返回跳转。
【六】类似数组的基址与变址寄存器
理解起来很简单,数组就是内存中一段连续排列的数据结构,通常使用数组名表示数组的起始位置,通过索引表示元素的相对位置,即相对起始位置的偏移量。
基址寄存器保存基址,类似数组名,变址寄存器保存偏移量,类似索引
如:基址寄存器:0100
,变址寄存器:0036
实际内存地址=基址寄存器+变址寄存器0136