CPU的控制器大致有哪些功能和其具体原理?

——解析指令,根据指令指挥其他部件协调工作。

指令该如何设计?

4.1 指令格式

指令的基本格式.pdf

4.1.1 指令的基本格式

操作码、地址码的概念

  • 指令(又称机器指令)是指计算机执行某种操作的命令,是计算机运行的最小功能单位

  • 一台计算机的所有指令的集合构成该机的指令系统,也称指令集

  • 一台计算机只能执行自己指令系统中的命令,不能执行其他系统的指令(X86架构、ARM架构)

  • 指令=操作码(OP)+地址码(A),操作码指明了做什么,地址码指明了对谁动手

    • 有的指令不需要地址码(如:停机)

根据地址码数目不同分类

根据地址码数目不同,可以将指令分为零地址指令、一地址指令、二地址指令

  • 零地址指令

    • 不需要操作数的操作,如空操作、停机、关中断等指令

    • 操作数隐含,如堆栈计算机,两个操作数隐含存放在栈顶和次栈顶,计算结果压回栈顶(参考后缀表达式求值

  • 一地址指令 + 操作数

    • 只需要单操作数,如加1、减1、取反、求补等

      • 指令含义: 指某个主存地址, 表示 所指向的地址中的内容

      • 完成一条指令需要 3 次访存:取指令,读出,写回

    • 需要两个操作数,但其中一个操作数隐含在某个寄存器,如隐含在ACC

      • 指令含义:

      • 完成一条指令需要2次访存:取指令,读 ,写回寄存器不需要访存

  • 二地址指令 +目的操作数+源操作数

    • 需要两个操作数的算数运算、逻辑运算相关指令

    • 指令含义:

    • 完成一条指令需要 4 次访存:取指令,读,读,写

  • 三地址指令 + 目的操作数 + 源操作数 + 结果

    • 需要两个操作数的算数运算、逻辑运算相关指令

    • 指令含义:

    • 完成一条指令需要4次访存:取指令,读,读,写

  • 四地址指令 + 目的操作数 + 源操作数 + 结果+下址

    • 需要两个操作数的算数运算、逻辑运算相关指令

    • 指令含义:为下一条将要执行指令的地址

    • 正常情况下取指令之后 PC+1,指向下一条指令;四地址指令中执行指令后,将 PC 的值修改为所指的地址

    • 完成一条指令需要4次访存:取指令,读,读,写

  • 若指令总长度固定不变,地址码数量越多,则单个地址码越短,寻址能力越差

根据指令长度分类

关于字长

  • 指令字长是机器字长的多少倍:半字长指令、单字长指令、双字长指令。指令字长会影响到取指令所需要的时间

  • 定长指令字结构:指令系统中所有指令的长度均相等;

  • 变长指令字结构:指令系统中各种指令的长度可以不等;

根据操作码的长度不同分类

  • 定长操作码:指令系统中所有指令的操作码长度都相同——控制器的译码电路设计简单,但灵活性较低

  • 可变长操作码:指令系统中各种指令的操作码长度可变——控制器的译码电路设计复杂,但灵活性较高

  • 位操作码字段的指令系统最大能够表示 条指令

根据操作类型分类

  • 数据传送类:进行主存与CPU之间的数据传送

    • LOAD:把存储器中的数据放到寄存器中

    • STORE:把寄存器中的数据放到存储器中

  • 运算类:算数逻辑操作+移位操作

    • 算数:加、减、乘、除、加1、减1、求补、浮点运算、十进制运算

    • 逻辑:与、或、非、异或、位操作、位测试、位清除、位求反

    • 移位:算数移位、逻辑移位、循环移位

  • 程序控制类:改变程序执行的顺序——转移操作

    • 无条件转移 JMP

    • 条件转移 JZJOJC

    • 调用和返回 CALLRETURN

    • 陷阱 Trap 与陷阱指令

  • 输入输出类:进行CPU与IO设备之间的数据传送

    • 输入输出操作:CPU寄存器与IO端口之间的数据传送(IO端口即IO接口中的寄存器)

4.1.2 定长操作码的指令格式

定长操作码

4.1.3 扩展操作码指令格式

扩展操作码指令格式.pdf

  • 定长指令字结构+可变长操作码→扩展操作码指令格式,不同地址数的指令使用不同长度的操作码(可以类比哈夫曼树

  • 设计扩展操作码指令格式需要注意以下两点:

    • 不允许短码是长码的前缀,即短操作码不能与长操作码的前面部分代码相同

    • 各指令的操作码一定不能重复

  • 通常情况下,对使用频率较高的指令,分配较短的操作码,从而尽可能减少指令译码和分析的时间

设地址长度为 ,上一层留出了 种状态,则下一层可扩展出 种状态(类比IPv4地址的子网划分)。如:

:设指令字长固定为16位,试设计一套指令系统满足有:15条三地址指令、12条2地址指令、62条一地址指令、32条零地址指令

指令数
15条三地址指令0000~1110(留1种)
12条二地址指令11110000~1011(留4种)
62条一地址指令11111100~1110
1111
0000~1111
0000~1101(留2种)
32条零地址指令111111111110~11110000~1111

4.1.4 指令的操作类型

指令的操作类型

4.2 指令的寻址方式

一个操作数在内存中可能占多个单元,怎样在指令中给出操作数的地址?

寻找的是虚拟地址

PC中存放着虚拟地址,而MAR中存放着物理地址

  • 现代计算机都采用字节编址的方式,即一个内存单元只能存放一个字节的信息。一个操作数可能占用多个内存单元,与多个内存地址对应。有两种不同的地址指定方式:大端方式和小端方式

    • 大端方式:指令中给出的地址是操作数的最高有效字节(MSB)所在的地址

    • 小端方式:指令中给出的地址是操作数的最低有效字节(LSB)所在的地址

4.2.1 指令寻址

指令寻址:确定下一条要执行的指令的存放地址。下一条欲执行指令的地址,始终由程序计数器PC给出

指令寻址.pdf

顺序寻址

  • 读入一个字,根据操作码判断这条指令的总字数 ,修改PC的值,

  • 根据指令的类型,CPU可能还要进行多次访存,每次读入一个字

跳跃寻址

  • 每一条指令的执行都分为“取指令”和“执行指令”两个阶段

  • 每次取指令后,PC一定会 ,之后执行到转移指令时会对PC的值进行修改

4.2.2 数据寻址

数据寻址:确定本条指令的地址码指明的地址(虚拟地址)

数据寻址1.pdf

数据寻址的方式较多,为了区别各种方式,在指令字中设一个字段,用来指明属于哪种寻址方式。

多地址指令=操作码(OP)+寻址特征+形式地址()+寻址特征+形式地址()……

直接寻址

  • 指令字中的形式地址 就是操作数的真实地址 ,即

  • 取指令访存1次,执行指令访存1次,共访存2次

第4章 指令系统

  • 优点:简单,指令执行阶段仅访问一次主存,不需要专门计算操作数的地址

  • 缺点: 的位数决定了该指令操作数的寻址范围;操作数的地址不易修改

间接寻址

  • 指令的地址字段给出的形式地址不是操作数的真正地址,而是操作数的有效地址所在的存储单元的地址,也就是操作数地址的地址,即

  • 取指令访存1次,执行指令访存2次,共访存3次

间接寻址

  • 优点:可扩大寻址范围(有效地址EA的位数大于形式地址A的位数);多级间接寻址便于编制程序(用间接寻址可以方便地完成子程序返回)

  • 缺点:指令在执行阶段要多次访存(一次间接寻址需要两次访存,多次寻址需要根据存储字的最高位确定几次访存)

寄存器寻址

  • 在指令字中直接给出操作数所在的寄存器编号,即 ,其操作数在由 所指的寄存器内

  • 取指令访存1次,执行指令访存0次,共访存1次

寄存器寻址

  • 优点:指令在执行阶段不访问主存,只访问寄存器,指令字短且执行速度快,支持向量/矩阵运算

  • 缺点:寄存器价格昂贵,计算机中寄存器个数有限

寄存器间接寻址

  • 寄存器 中给出的不是一个操作数,而是操作数所在主存单元的地址,即

  • 取指令访存1次,执行指令访存1次,共访存2次

寄存器间接寻址

  • 特点:与一般间接寻址相比速度更快,但指令的执行阶段需要访问主存(因为操作数在主存中)

隐含寻址

  • 不是明显地给出操作数的地址,而是在指令中隐含着操作数的地址(如:ACC或栈顶)

  • 取指令访存1次,执行指令访存0次,共访存1次

隐含寻址

  • 优点:有利于缩短指令字长

  • 缺点:需要增加存储操作数或隐含地址的硬件

立即寻址

  • 形式地址 就是操作数本身,又称为立即数,一般采用补码形式,# 表示立即寻址特征

  • 取指令访存1次,执行指令访存0次,共访存1次

立即寻址

  • 优点:指令执行阶段不访问主存,指令执行时间最短

  • 缺点: 的位数限制了立即数的范围

偏移寻址

偏移寻址:以某个地址作为起点,形式地址视为偏移量

数据寻址2_偏移寻址.pdf

基址寻址

以程序的起始存放地址作为起点

  • 将CPU中的基址寄存器(BR, Base Address Register)的内容加上指令格式中的形式地址 而形成的操作数的有效地址,即 (OS课中的“重定位寄存器”就是“基址寄存器”,详见装入的三种方式

  • 也可以采用通用寄存器作为基址寄存器,并在指令中指明要将哪个通用寄存器作为基址寄存器使用

基址寻址

基址寄存器是面向操作系统的,其内容由操作系统或管理程序确定。在程序执行过程中,基址寄存器的内容不变(作为基地址),形式地址可变(作为偏移量);当采用通用寄存器作为基址寄存器时,可由用户决定哪个寄存器作为基址寄存器,但其内容仍然是由操作系统决定

优点:可以扩大寻址范围(基址寄存器的位数大于形式地址A的位数);用户不必考虑自己的程序存于主存的哪一空间区域,有利于多道程序设计,以及可用于编制浮动程序(整个程序在内存里面的浮动)

变址寻址

程序员自己决定从哪里作为起点

将变址寄存器(IX, Index Register)的内容加上指令格式中的形式地址A而形成的操作数的有效地址,即 EA=(IX)+A

也可以采用通用寄存器作为变址寄存器,并在指令中指明要将哪个通用寄存器作为变址寄存器使用

变址寻址

变址寄存器是面向用户的,在程序执行过程中,变址寄存器的内容可由用户改变(IX作为偏移量),形式地址A不变(作为基地址)

优点:在数组处理过程中,可设定A为数组的首地址,不断改变变址寄存器IX的内容,便很容易形成数组中任一数据的地址,特别适合编制循环程序

相对寻址

以程序计数器PC所指地址作为起点

将程序计数器(PC, Program Counter)的内容加上指令格式中的形式地址A而形成的操作数的有效地址,即 EA=(PC)+A,其中A是相对PC所指地址(当前指令地址的下一个地址)的位移量,可正可负,用补码表示

image-20221018164333940

优点:如果操作数的地址不是固定的,它随着PC值的变化而变化,并且与指令地址之间总是相差一个固定值,因此便于程序浮动(一段代码在程序内部的浮动)。相对寻址广泛应用于转移指令

堆栈寻址

操作数存放在堆栈中,隐含使用堆栈指针(SP, Stack Pointer)作为操作数地址

数据寻址3_堆栈寻址.pdf

堆栈是存储器(或专用寄存器组)中一块特定的按“后进先出(LIFO)”原则管理的存储区,该存储区中被读写单元的地址是用一个特定的寄存器给出的,该寄存器称为堆栈指针(SP)

  • 硬堆栈:寄存器堆栈,速度快成本高,不访存

  • 软堆栈:从主存中划出一段区域来做堆栈,速度慢成本低,访存1次

堆栈可用于函数调用时保存当前函数的相关信息

4.3 程序的机器级代码表示

4.3.1 常用汇编指令介绍

机器级代码考试要求

  • 只需要关注X86汇编语言,其他语言会详细注释

  • 题目中给出某段简单程序的C语言、汇编语言、机器语言表示,能结合C语言看懂汇编语言的关键语句(常见指令、选择结构、循环结构、函数调用)

  • 汇编语言、机器语言一一对应,要能结合汇编语言分析机器语言指令的格式、寻址方式

  • 不会考:将C语言人工翻译为汇编语言或机器语言

X86语言指令基础

汇编语言与机器语言一一对应,汇编语言与机器语言都属于机器级代码表示

指令的作用?

①改变程序执行流

②处理数据

指令格式

指令格式:操作码+地址码

  • 操作码——怎么处理?

  • 地址码——数据在哪?

    • 寄存器里——在指令中给出“寄存器名”,X86架构的CPU有哪些寄存器?

    • 主存里——在指令中给出“主存地址”,如何在指令中指明读写长度?

    • 指令里——在指令中直接给出要操作的数,也就是立即寻址;汇编指令中可用十进制表示,也可用十六进制(常以h结尾)

mov指令为例

mov 目的操作数d,源操作数s:将源操作数s(source)复制到目的操作数d(destination)所指的位置

mov eax, ebx					#将 寄存器ebx的值 复制到 寄存器eax
mov eax, 5						#将 立即数5 复制到 寄存器eax
mov eax, dword ptr [af996h]		#将 内存地址af996h所指的32bit值 复制到 寄存器eax
mov byte ptr [af996h], 5		#将 立即数5 复制到 内存地址af996h所指的一字节中
 
mov eax, dword ptr [ebx]		#将 eax所指主存地址的32bit 复制到 eax寄存器中(寄存器间接寻址)
mov eax, [ebx]					#未指名读写长度,默认32bit
mov eax, dword ptr [ebx+8]		#将 ebx+8(数值加减)所指主存地址的32bit 复制到 eax寄存器

如何指明读写长度?

  • dword ptr [地址]——双字,32bit

  • word ptr [地址]——单字,16bit

  • byte ptr [地址]——字节,8bit

寄存器

X86架构CPU有哪些寄存器?

  • EAX, EBX, ECX, EDX:通用寄存器(X=未知,E=Extended, 32bit)

    • AX, BX, CX, DX:只使用通用寄存器更低的16bit

    • 两个高低字节还可分别作为两个8位寄存器单独使用,分别为AH和AL……

  • ESI, EDI:变址寄存器(I=Index, S=Source, D=Destination),可用于线性表、字符串的处理

  • EBP, ESP:堆栈基指针(Base Pointer),堆栈顶指针(Stack Pointer),用于实现函数调用

常用的X86汇编指令

最终结果将放在 d 的位置,所以目的操作数 d 不可以是常量,且不允许两个操作数都来自主存

算术运算类

  • 加法(add) add d, s:计算 ,结果存入 d

  • 减法(substract) sub d, s:计算 ,结果存入 d

  • 乘法(multiply) mul d, s imul d, s:无符号数/有符号数 ,结果存入 d

  • 除法(divide) div s idiv s:无符号数/有符号数 ,商存入eax,余数存入edx(被除数被提前放入 edxeax 寄存器中,并且进行了位数扩展,用64位被除数除以32位除数)

  • 取负数(negative) neg d:将 d 取负数,结果存入 d

  • 自增(increase) inc d:执行 d++,结果存入 d

  • 自减(decrease) dec d:执行 d--,结果存入 d

逻辑运算类

  • 与(and) and d, s:将d、s逐位相与,结果放回d

  • 或(or) or d, s:将d、s逐位相或,结果放回d

  • 非(not) not d:将d逐位取反,结果放回d

  • 异或(exclusive or) xor d, s:将d、s逐位异或,结果放回d

  • 左移(shift left) shl d, s:将d逻辑左移s位,结果放回d(通常s是常量)

  • 右移(shift right) shr d,s:将d逻辑右移s位,结果放回d(通常s是常量)

其他

  • 用于实现分支结构、循环结构的指令:cmp test jmp jxxx

  • 用于实现函数调用的指令:push pop call ret

  • 用于实现数据转移的指令:mov

AT&T格式 vs Intel格式

AT&T格式:Unix、Linux的常用格式

Intel格式:Windows的常用格式

AT&T格式x86格式
目的操作数 d,源操作数 sop s, dop d, s
寄存器的表示mov %ebx, %eaxmov eax, ebx
立即数的表示mov $985, %eaxmov eax 985
主存地址的表示mov %eax, (af996h)mov (af996h), eax
读写长度的表示movb $5, (af996h)
movw $5, (af996h)
movl $5, (af996h)
mov byte ptr [af996h], 5
mov word ptr [af996h], 5
mov dword ptr [af996h], 5
主存地址偏移量的表示movl -8(%ebx), %eax
movl 4(%ebx, %ecx, 32), %eax
mov eax, [ebx - 8]
mov eax, [ebx+ecx*32+4]

4.3.2 过程调用的机器级表示【暂缺】

后续补上?

  • 函数调用指令call:将PC旧值压栈保存;设置PC的新值,无条件转移至被调用函数的第一条指令

  • 函数返回指令ret :从函数的栈帧顶部找到PC的旧值,将其出栈并恢复到程序计数器PC

假设过程 A(调用者)调用过程 B (被调用者),过程调用的执行步骤如下:

  1. A 将入口参数(实参)放在 B 能访问到的地方

  2. A 将返回地址存到特定的地方,然后将控制转移到 B (call 指令)

  3. B 保存 A 的现场(通用寄存器的内容),并为自己的非静态局部变量分配空间

  4. 执行过程Q

  5. B 恢复 A 的现场,将返回结果放到 A 能访问到的地方,并释放局部变量所占空间

  6. B 取出返回地址,将控制转移到 A (ret 指令)

第4章-过程调用.drawio

4.3.3 选择语句的机器级表示

每取出一条指令,PC自动+“1”,指向下一条指令

X86架构中,程序计数器PC(Program Counter)通常被称为IP寄存器(Instruction Pointer)

  • 无条件转移指令 jmp <地址>:PC无条件转移至<地址>,类似C语言里的goto语句

    • <地址> 可以用常数直接给出或者来自于寄存器或主存

    • 可以使用“标号”锚定位置,名字可以自己取

	mov eax, 7
	mov ebx, 6
	jum NEXT
	mov ecx, ebx
	NEXT:
	mov ecx, eax
  • 条件转移指令 jXXX,一般要与cmp指令一起使用

    • je <地址>:jump when equal,若 a==b 则跳转

    • jne <地址>:jump when not equal,若 a!=b 则跳转

    • jg <地址>:jump when greater than,若 a>b 则跳转

    • jge <地址>:jump when greater than or equal to,若 a>=b 则跳转

    • jl <地址>:jump when less than,若 a<b 则跳转

    • jle <地址>:jump when less than or equal to,若 a<=b 则跳转

	if (a > b)
		c = a;
	else
		c=b;
    mov eax, 7		#假设变量a=7,存入eax
    mov ebx, 6		#假设变量b=6,存入ebx
    cmp eax, ebx	#比较变量a和b
    jle NEXT		#若a<b,转移到NEXT:
    mov ecx, eax	#假设用ecx存储变量c,令c=a
    jmp END			#无条件转移到END:
    NEXT:
    mov ecx, ebx	#假设用ecx存储变量c,令c=b
    END:
  • bxxx:branch

写汇编语言代码时,一般会以函数名作为“标号”,标注该函数指令的起始地址,条件转移时便可以从函数的起始地址偏移

扩展:cmp指令的底层原理

cmp a, b 本质上是进行 减法运算,并生成标志位 OF(溢出标志)、ZF(零标志)、CF(进位/错位标志)、SF(符号标志),根据标志位结果来判断 之间的大小关系

  • 无符号数减法关注:ZF(零标志)、CF(进位/错位标志)

  • 有符号数减法关注:ZF(零标志)、OF(溢出标志)、SF(符号标志)

ALU 的每次运算的标志位都自动存入PSW程序状态寄存器(Intel称其为标志寄存器)

je <地址>		#若a==b则跳转,ZF==1				//a-b结果为0
jne <地址>		#若a!=b则跳转,ZF==0				//a-b结果不为0
				#SF==OF,代表大于等于0,即:结果为负且发生溢出 或 结果为不为负且未发生溢出
jg <地址>		#若a>b则跳转,ZF==0 && SF==OF	//a-b结果不为0且大于等于0
jge <地址>		#若a>=b则跳转,SF==OF			//a-b结果大于等于0
jl <地址>		#若a<b则跳转,SF!=OF				//a-b结果小于0
jle <地址>		#若a<=b则跳转,ZF==1 || SF!=OF	//a-b结果为0或小于0

4.3.4 循环语句的机器级表示

用条件转移指令实现循环

//求1+2+...+100
 
//用for实现
int result =0;
for (int i=1; i<=100; i++){
	result = result + i;
}
 
//用while实现
int i=1;
int result =0;
while(i<=100){
	result = result + i;
	i++;
}
mov eax, 0		#用eax保存result,初始值为0
mov edx, 1		#用edx保存i,初始值为1
 
cmp edx, 100	#若i>100,跳转到L2
jg L2
 
L1:				#循环主体
add eax, edx	#实现result = result + i
inc edx			#inc 自增指令,实现i++
 
cpm edx, 100	#若i<=100,跳转到L1
jle L1
 
L2:				#跳出循环主体

用条件转移指令实现循环,需要4个部分构成:

  1. 循环前的初始化

  2. 是否直接跳过循环

  3. 循环主体

  4. 是否继续循环

用loop指令实现循环

for (int i=500; i>0; i--){
	做某些处理;
}//循环500轮
mov ecx 500		#用ecx作为循环计数器,这里是ecx的特殊功能,不能用其他寄存器
Looptop:		#循环的开始
做某些处理
loop Looptop	#ecx--,若ecx!=0,跳转到Looptop
 
 
#等价于下列代码
dec ecx
cpm ecx, 0
jne Looptop

理论上,能用loop指令实现的功能一定能用条件转移指令实现

使用loop指令可能会使代码更清晰简洁

loopX指令

  • loopnz:当ecx!=0 && ZF==0时,继续循环

  • loopz:当ecx!= && ZF==1时,继续循环

4.4 CISC 和 RISC 的基本概念

CISC 和RISC是指令系统的两种设计方向

CISC:Complex Instruction Set Computer,复杂指令系统计算机

  • 设计思路:一条指令完成一个复杂的基本功能

  • 代表:X86架构,主要用于笔记本、台式机等

  • 采用“存储程序”的设计思想,由一个比较通用的电路配合存储部件完成一条指令

RISC:Reduced Instruction Set Computer,精简指令系统计算机

  • 设计思路:一条指令完成一个基本动作,多条指令组合完成一个复杂的基本功能

  • 代表:ARM架构,主要用于手机、平板等

  • 一条指令一个电路,电路设计相对简单,功耗更低

80-20规律:典型程序中80%的语句仅仅使用处理机中的20%指令

CISCRISC
指令系统复杂、庞大简单、精简
指令数目一般大于200条一般小于100条
指令字长不固定定长
可访存指令不加限制只有Load/Store指令
各种指令执行时间相差较大绝大多数在一个周期内完成
各种指令使用频度相差很大都比较常用
通用寄存器数量较少
目标代码难以用优化编译生成高效的目标代码程序采用优化的编译程序,生成代码较为高效
控制方式绝大多数为微程序控制(效率低)绝大多数为组合逻辑控制(效率高)
指令流水线可以通过一定方式实现必须实现

考前记一记