- 计算机构成
CPU、存储器和输入输出设备,通过总线连接和通信。
- 处理器
CPU的职责
CPU的工作是从内存(RAM)提取指令、译码分析并执行指令(执行指令本质上是从内存读取数据到寄存器中,进行运算,将运算结果写回到内存)。
此外CPU直接与IO设备通信,IO设备向CPU发送数据,IO设备接收CPU发送的数据(当然,这些数据也是要经过内存的,所以也没有超脱提取和执行指令这个本职工作)。
CPU的构成
CPU主要由 控制单元 和 算术逻辑单元(ALU)两部分组成,控制单元从内存提取指令并译码(或者说解码),ALU进行算术运算(加减乘除等)和逻辑运算(或且异或)。
从功能上看,CPU由 寄存器、控制器、运算器 和 时钟组成,各部分间通过电信号通信。
寄存器:用于暂存指令、数据和地址,可以看做是比主存速度更快容量更小的存储器。
控制器:负责将内存中的指令、数据读入寄存器,并根据指令结果控制计算机。
运算器:负责运算从内存读入寄存器的数据。
时钟:负责发出CPU开始计时的时钟信号。
下面重点了解CPU的寄存器。
CPU的寄存器
累加寄存器:存储运行的数据和运算后的数据。
标志寄存器:反映CPU的状态,包含CPU优先级、CPU状态(用户态还是内核态)和各种控制位。
程序计数器(PC):保存下一个要提取的指令所在的内存地址。
指令寄存器:存储正在运行的指令。
栈寄存器:存储某个进程的内存栈的栈顶指针(这个栈保存着相关函数调用(即过程调用)的现场信息,包括函数的参数、局部变量和未在寄存器中保存的临时变量)。
基址寄存器:存储某个数据所在的内存段或页的起始地址。
变址寄存器:存储某个数据所在的内存段或页的相对地址。
通用寄存器:存储临时变量等任意数据。
其中,程序计数器、累加寄存器、标志寄存器、指令寄存器和栈寄存器一般都只有1个,其他寄存器有多个。
顺序执行、条件分支和循环机制
程序执行时,PC的初始值是程序第一条指令的地址。
顺序执行程序的指令时,CPU的控制器按PC所指的地址获取指令到指令寄存器中,然后分析和执行该指令。PC的值加1,指向下一条要执行的指令。
因此可以说程序计数器控制着程序的流程。
一段程序之所以要先装入内存才能运行,而无法在磁盘运行是因为CPU的程序计数器上存储的是内存地址,而不是磁盘地址,因此CPU只能直接读取存在内存上的指令。
顺序执行是每执行一条指令,程序计数器的值就+1;
条件分支是根据条件让程序计数器的值指向程序中任意地址的指令;
循环则是让程序计数器重复从循环的开始地址的指令开始往下执行,然后又重复跳回循环的开始地址;
条件和循环分支会使用到 jump(跳转指令),根据当前指令判断是否跳转到指定的某个指令还是跳转到另一个指令。
每一个指令(在累加寄存器)的运算结果无论是正数、负数还是零,标志寄存器都会保存结果的状态(累加寄存器保存结果的具体值,标志寄存器保存结果是正是负还是零)。
标志寄存器本质是存储了一串二进制串,二进制串上的不同位表示不同的状态信息,它的前3个字节位分别代表本次运算结果是正数、零还是负数。
条件分支和循环分支就是根据标志寄存器中计算结果为 正数/零/负数 以及其他标志位的状态信息决定是否jump跳转指令。
对于高级语言中的一个比较语句 如 if a > b,其本质是令 a和b做减法运算,在根据运算结果在标志寄存器的前3个位判断是否跳转。
函数调用机制
函数调用机制是通过 “调用函数时把程序计数器的值设置为函数的存储地址(call指令),函数执行结束时把程序计数器的值设置回函数调用的下一条指令的地址(return 指令)” 来实现的。
开始执行函数前,会执行call指令把调用函数完毕后要执行的下一条指令地址(即上图中的0154)存到栈中(这个栈是进程或线程创建之初,系统分配给线程或进程的保存过程调用产生的临时变量的内存空间),然后把程序计数器的值置为函数的入口地址;函数执行完毕后,会执行return指令,把保存到栈中的地址设置回程序计数器上。
从内存中定位数据
操作系统管理内存时,会将整个物理内存划分为多个区域(页或段),指令中的某个操作数A的地址会以“它所在页面的开始地址 + 它所在该页面内的相对地址”的形式表示,A所在页面的开始地址(该页面第一个字节的地址)保存在基址寄存器,A在该页面内的相对地址保存在变址寄存器,这样CPU的控制器就可以根据 基址寄存器的值 + 变址寄存器的值找到数据A在内存中的实际地址。
当轮到下一条指令要执行的时候,这个基址寄存器和变址寄存器就会更新为新指令中操作数的地址。
这就像访问数组元素一样,基址寄存器相当于数组变量的地址,变址寄存器相当于数组下标。
CPU执行过程
前面我们提过,CPU的工作是从内存(RAM)提取指令、译码分析并执行指令。
更具体的来说,CPU的工作分为5个阶段:取指令、指令译码、执行指令、访问取数、结果写回。
取指令:CPU的控制器根据程序计数器的值从内存读取下一条要执行的指令到CPU的寄存器中。
指令译码:取指令后,进入译码阶段,指令译码器对指令拆分和解释,识别出不同指令类别和操作数。
执行指令:具体实现指令的功能,包括访问取数 + 算数/逻辑运算 + 结果写回。
访问取数:根据指令的操作数所在的内存地址,从内存中提取操作数用于运算。
结果写回:将指令执行结果写到CPU寄存器或写回到主存中。
- 存储器
存储器是一个分层的存储体系,按照速度、容量和成本划分:
顶层是CPU内部寄存器,存取寄存器中的数据没有延迟,容量单位为K
第二层是高速缓存,一般放在CPU内或里CPU很近的地方。当CPU需要读取某个数据时会先从高速缓存读取,如果命中则直接使用。如果未命中则从主存中读取并放入高速缓存以备之后使用。容量单位为 M
第三层内存(又称主存或RAM,即随机存取存储器),CPU能够直接存取内存、高速缓存和寄存器的信息,但不能直接存取磁盘的信息。因此机器执行的指令和用到的数据要预先放到内存或高速缓存或寄存器中。然而前三层的数据是容易丢失的,关电源后就会丢失。容量单位为G。
下一层是磁盘(称外存或辅存),可永久保留数据,容量单位为百G或T。
内存分为3类
随机存储器(RAM):我们嘴里常说的内存是指RAM,可读可写,物理结构类似数组, 内存的每个字节的空间紧密相连,可随机读取。
只读存储器(ROM):数据只读,只能顺序读取,不能写入数据。机器停电时数据不会丢失。
高速缓存:位于主存和CPU之间的一个比主存更快的存储器。
内存的结构
内存由各种的IC电路组成,每个IC(IC即集成电路卡)是一个完整的结构,拥有自己的电源、用于寻址的地址信号引脚、用于读写数据的数据信号引脚 和 控制信号引脚等。
图中凸起是内存IC的引脚,电信号通过引脚流入和流出内存IC。
数据信号用于读写数据,数据信号的个数决定了内存IC一次可以读写几个位,图中有D0~D7这8个数据信号,因此一次可读写 8bit = 1byte的数据。
地址信号决定该内存IC可以存储多少容量的数据,图中有 A0~A9这10个地址信号,可以指定 2^10 = 1024 = 1K的数据,因此容量为1K。
控制信号决定本次内存操作是读操作还是写操作。
一个内存IC通常会有更多的引脚,存储更多的数据。
内存读写过程如下:
1. 给VCC和GND通电,将WR置为1表示写入操作,用A0~A9指定数据存储场所,将数据的值输入给D0~D7的数据信号,即可完成向内存IC写入数据。
2.读取数据则将RD置为1即可。
3. RD和WR都为0时,无法进行写入和读取操作。
- IO设备
IO设备(输入输出设备)是人机交互的工具,由控制器和设备硬件本身两部分组成。
控制器是IO设备的电子部分(硬件的形式表现为印制电路卡,所以控制器本质上也是一个硬件),实现设备操作与系统操作的同步。控制器本身有一些缓冲区和一组专用寄存器,负责在外部设备和本地缓冲区之间传输数据时缓存数据。
设备本身实际上隐藏在控制器后面,操作系统总是与控制器打交道,而非与设备本身直接交互。
由于IO设备有很多,对应的设备控制器类型也有很多,因此操作系统内置了能向控制器发送命令并接收控制器响应的设备驱动程序。设备驱动程序在不同操作系统上的不同控制器上是不同的,理论上驱动程序可运行在核心之外,但操作系统一般都会将其放到核心内运行。
- 总线
分为3种(这3类总线对应CPU上的3类信号引脚):
数据总线:在计算机各部件间传输数据的通道,其宽度随字长决定,如32位结构的数据总线是32根。数据总线是双向的。
地址总线:用来表示CPU要读写的数据的地址,他可以是存储器的地址,也可以是IO设备中控制寄存器或数据寄存器的地址。
控制总线:在计算机各部件间传输控制信号。
当多个设备要往总线发信号或传数据前,会先监听总线是否空闲,空闲才能占用总线,使用后需要释放总线。