计算机组成原理王道笔记
王道计算机组成原理笔记。
文章目录
- 前言
- 零、名词汇总
- 一、计算机系统概述
- 二、数据的表示和运算
- 三、存储系统
- 四、指令系统
- 五、中央处理器
- 六、总线
- 七、输入/输出系统
前言
本博客主要内容来自于王道计算机组成原理的课程PDF,不足之处会粘贴王道课本的段落,帮助自己理解。
\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad
————来自一位科憨。
零、名词汇总
第一章:计算机系统概述
计算机系统的组成、硬件系统、软件系统、软硬件逻辑功能上的等效性。
冯-诺依曼机的六大特性。
现代计算的五大功能部件、输入设备、输出设备、存储器、运算器、控制器。
主存储器、辅助存储器、主存储器的工作方式、主存储器的基本组成、存储体、时序逻辑控制、MAR、MDR、存储元、存储单元、存储字长、存储字长与字节的关系、MAR与PC及存储单元的关系、MDR与存储字长的关系、现代计算机MAR与MDR及Cache的存放位置。
运算器的功能、运算器的核心、ALU、通用寄存器组(ACC、MQ、X、IX、BR),PSW、暂存寄存器。
控制器的功能、CU、ID、IR、PC、PC与MAR之间有一条直接通路,IR的内容来自MDR。
CPU的组成、主机、外部设备、系统总线。
系统软件、应用软件、机器语言、汇编语言、高级语言、翻译程序、汇编程序/汇编器、解释程序/解释器、编译程序/编译器。
微程序机器M0、机器语言机器M1、操作系统机器(虚拟机器)M2、汇编语言机器(虚拟机器)M3、高级语言机器(虚拟机器)M4。
存储程序的工作方式。
-
控制流驱动方式:如冯-诺依曼结构的CPU,是从程序存储器拿到操作指令后,再去数据存储器中取操作数进行运算。
-
数据流驱动方式:程序中各指令的执行顺序仅由指令间的数据依赖关系决定,只有指令所需的数据全部准备好后才能激发相应的指令执行,结果又流向等待这一数据的下一条指令。
-
单指令流单数据流:指令串行执行,每个时钟周期CPU只能处理一个数据流,如冯-诺依曼结构。
-
单指令流多数据流:用一个控制器控制多个处理器同时对一组数据(向量)进行处理,如阵列计算机、向量处理机、图形处理设备(GPU)。
-
多指令流单数据流:不存在。
-
多指令流多数据流:多个控制器控制多个处理器,即多处理器系统。
解释程序的特点是翻译一句执行一句,不会生成目标程序,如Shell、JavaScript、Python;编译程序将高级语言源程序一次全部翻译成目标程序,如C、C++。
数据库系统是指在计算机系统中引入数据库后的系统,一般由数据库、数据库管理系统、应用系统、数据库管理员构成,其中数据库管理系统是系统软件。
机器字长及与通用寄存器宽度的关系、数据通路带宽、数据通路、主存容量、主存容量与MAR及MDR的关系、吞吐量与主存存取周期的关系、响应时间、主频、CPU时钟周期、CPI、CPU执行时间MIPS、MFLOPS、GFLOPS、TFLOPS、PFLOPS、EFLOPS、ZFLOPS、基准程序、系列机、兼容、软件可移植性、固件。
数据字长是数据总线一次能并行传送的信息的位数,它可以不等于MDR的位数。
机器字长是指CPU内部用于整数运算的数据通路的宽度,CPU内部的数据通路是指CPU内部的数据流经的路径及路径上的部件,主要是CPU内部进行数据运算、存储和传送的部件,这些部件的宽度基本上要一致才能相互匹配,因此,机器字长等于CPU内部用于整数运算的运算器ALU的位数和通用寄存器的位数。
一般情况下,基准测试程序能够反映机器性能的好坏,但是由于基准程序中的语句存在频度差异,因此运行结果不能完全说明问题。
第二章:数据的表示与运算
机器数与真值
错题:
解析:从移码的特性易知,
11111111
11111111
11111111与
00000000
00000000
00000000分别是最大正数与最小负数。其中
11111111
11111111
11111111真值为127,
00000000
00000000
00000000真值为-128,当x=127时,-x=-127,其补码为
10000001
10000001
10000001,未发生溢出,而当x=-128时,-x=128,其补码为,
100000000
100000000
100000000故发生溢出。
第三章.存储系统
主存、辅存、高速缓冲处理器、磁表面存储器、磁芯存储器、半导体存储器、光存储器、随机存储器、只读存储器、串行访问存储器、顺序存取存储器、直接存取存储器、易失性存储器、非易失性存储器、破坏性读出、非破坏性读出。
存储容量、单位成本、存储速度。
多级层次的存储系统、Cache-主存层、主存-辅存层。
第七章:输入/输出系统
外部接口、内部接口、数据缓冲寄存器、状态/控制寄存器、地址译码和I/O控制逻辑、外设界面控制逻辑、数据线、地址线、控制线、接口与端口、统一编制(存储器映射方式)、独立编制(I/O映射方式)。
- 在统一编址的情况下,没有专门的I/O指令,因此需要用访存指令来实现I/O操作,区分存储单元和I/O设备靠的是它们各自不同的地址码。
- 磁盘驱动器向盘片磁道记录数据时采用串行的方式写入。
- 当有多个中断请求同时出现时,中断服务程系统必须能从中选出当前最需要给予响应的且最重要的中断请求,这就需要预先对所有的中断进行优先级排队,这个工作可由中断判优逻辑来完成,排队的规则可由软件通过对中断屏蔽寄存器进行设置来确定。
- Cache并不能触发中断请求,Cache是CPU与主存之间的一种高速缓存,它存储了最近被访问的数据和指令,以提高访问速度。当CPU需要读取或写入内存时,它首先检查缓存中是否有所需的数据,如果有则可以直接访问缓存,否则需要从主存中获取数据。因为缓存是在CPU和主存之间的一个中介层,所以当中断请求发生时,CPU需要立即停止当前正在执行的任务并处理中断。此时,缓存中的数据可能没有及时地同步到主存中,如果缓存可以提出中断请求,那么这些数据将会丢失,导致系统出现错误。因此,为了确保系统的正确性和稳定性,缓存通常不能直接提出中断请求,而是通过一些机制来延迟处理中断请求,并在合适的时候将缓存中的数据同步到主存中,以避免数据丢失。
- 虚拟存储器失效如缺页等,会触发中断;浮点数运算下溢直接当做机器零处理,不会引发中断;浮点数上溢表示超过了浮点数的表示范围,属于内中断。
- 每条指令执行结束后,CPU会统一扫描各个中断源,然后进行判优来决定响应哪个中断源,而不是在每条指令的执行过程中这么做。
- 中断服务程序的最后指令通常是中断返回指令,与无条件转移指令不同,它不仅要修改PC的值,还要将CPU中所有寄存器都恢复到中断前的状态。
- 重新启动应当等待其他任务完成后再进行,优先级低于程序性中断和访管中断,访管指令紧迫,优先级高于程序性中断,也高于外部中断(内部异常一般高于外部中断)。
- 在中断响应周期中,由中断隐指令将允许中断触发器置0,而非关中断指令。
- 在DMA方式中,由外部设备向DMA控制器发送DMA请求信号,然后由DMA控制器向CPU发出总线请求信号,在DMA方式中,DMA控制器在传送期间有总线控制权,这时CPU不能响应I/O中断。
- 每个机器周期结束后,CPU就可响应DMA请求,注意,DMA在与主存交互数据时通过周期窃取方式,窃取的是存取周期。
- DMA请求的响应时间可以发生在每个机器周期结束时,只要CPU不占用总线。
- DMA的优先级高于外中断,包括可屏蔽、不可屏蔽中断。
- DMA传送数据时,挪用周期不会改变CPU现场,因此无需占用CPU的程序计数器和寄存器。
- 周期挪用法由DMA控制器挪用一个或几个主存周期来访问主存,传送完一个数据字后立即释放总线,是一种单字传送方式,每个字传送完后CPU可以访问主存,而无需等待整块数据传输完成。而停止CPU访问法则是在整块数据的传送过程中,使CPU脱离总线,停止访问主存。
- 用户态与核心态下CPU均能检测和响应中断(否则无法实现中断嵌套)。
- CPU只有在检测到中断请求信号后才会进入中断响应周期,此时CPU一定处于中断允许状态,否则无法响应该中断。当所有中断源都被屏蔽时,CPU不会检测到任何中断请求信号。
- 中断响应周期是指当CPU采用中断方式实现主机与I/O交换信息时,CPU在每条指令执行阶段结束前,都要发中断查询信号,以检测是否有某个I/O提出中断请求。如果有请求,CPU则要进入中断响应阶段,又称中断周期。简单来说中断响应周期就是计算机在找有没有中断请求的那段时间。所以在中断响应周期一定是开中断的!
- 中断响应周期是指当CPU采用中断方式实现主机与I/O交换信息时,CPU在每条指令执行阶段结束前,都要发中断查询信号,以检测是否有某个I/O提出中断请求。
一、计算机系统概述
1.2计算机系统层次结构
1.2.1计算机系统的组成
计算机系统由计算机硬件与计算机软件共同组成。
- 计算机硬件:计算机系统中实际物理装置的总称。
- 计算机软件:在硬件上运行的程序和相关数据以及文档。
计算机系统的好坏由计算机硬件与计算机软件共同决定,通常来说,一个功能用硬件实现后的执行效率高于用软件实现。
软硬件逻辑上的等效性:一个功能既可以用硬件实现,也可以用软件实现。如,对于乘法运算,既可设计一个专门的硬件电路实现,也可通过软件的方式执行多次加法运算实现。
1.2.2计算机硬件
1.冯-诺依曼机思想
冯-诺依曼机采用存储程序的方式进行工作。
2.计算机的功能部件
1.2.3计算机软件
1.2.4计算机系统的层次结构
1.2.5计算机系统的工作原理
1.3计算机性能指标
二、数据的表示和运算
本章的部分次序是自己编的,部分内容参考袁版教材,便于理解。
2.1数据的存储形式与进位计数制
2.1.1真值与机器数
2.1.2有符号数与无符号数
计算机系统内部的所有信息都是使用二进制进行编制,且参与运算的数分为有符号数和无符号数两大类,数一般存储在寄存器中,如通用寄存器,其位数与机器字长相等。当存放有符号数时,需留出位置存放符号,故而机器字长一定时,有符号整数和无符号整数的范围并不相同,如机器字长为 16 16 16位时,无符号整数表示范围为 0 − > 65535 0->65535 0−>65535,而有符号整数的表示范围为 − 32768 − > + 32767 -32768->+32767 −32768−>+32767(补码表示)。
2.1.3不同进制数之间的相互转换
(以上是十进制转二进制,故"基"为2,当转为四进制、八进制时,基应当为4、8)
快速转换方法:
−
11
/
16
=
−
(
1
/
2
+
1
/
8
+
1
/
16
)
=
−
(
2
−
1
+
2
−
3
+
2
−
4
)
=
−
0.1011
-11/16=-(1/2+1/8+1/16)=-(2^{-1}+2^{-3}+2^{-4})=-0.1011
−11/16=−(1/2+1/8+1/16)=−(2−1+2−3+2−4)=−0.1011
2.2无符号数的表示
2.2.1无符号数的表示
无符号数是指编码的二进制位全为数值位而无符号位,此时默认其符号为正,常用无符号数进行地址运算、表示指针。
2.2.2无符号数的加法运算
99
=
64
+
32
+
2
+
1
=
(
1100011
)
2
99=64+32+2+1=(1100011)_2
99=64+32+2+1=(1100011)2
当最高位产生进位时,即超出
0
−
255
0-255
0−255的表示范围,就会自动将最高位舍去,相当于是作
2
n
=
2
8
=
256
2^n=2^8=256
2n=28=256的模运算。
2.2.3无符号数的减法
此处运算时最高位进位为
1
1
1,会被自动舍去,计算结果仍然正确,由后续知识可知,对于符号数而言,溢出标志为
C
i
n
⊕
C
o
u
t
=
0
⊕
0
=
0
C_{in} \oplus C_{out}=0 \oplus 0=0
Cin⊕Cout=0⊕0=0,故并未发生溢出,即并未超出表示范围。
2.3有符号数:定点表示
有符号数根据小数点的位置是否固定,在计算机中有定点表示和浮点表示两种,在现代计算机中,通常用定点补码整数表示整数,定点原码小数表示浮点数的尾数部分,用移码表示浮点数的阶码部分。
2.3.1原码
用机器数的最高位表示数的符号,其余各位表示数的绝对值。
源码与真值的对应关系直观,与真值的转换简单,且用原码实现乘除运算简便,但
0
0
0的表示不唯一,且加减运算复杂,在计算机中,通常用定点原码小数表示浮点数的尾数部分。
2.3.1.1整数的原码
2.3.1.2小数的原码
2.3.2补码
在现代计算机中,通常用定点补码整数表示整数。
2.3.2.1前置知识:补数
以模
12
12
12为例,在模
12
12
12中,
+
9
+9
+9与
−
3
-3
−3是等价的,它们对
12
12
12而言互为补数,即
−
3
=
+
9
(
m
o
d
12
)
-3=+9(mod 12)
−3=+9(mod12),同理,
−
4
=
8
(
m
o
d
12
)
-4=8(mod 12)
−4=8(mod12),
−
5
=
7
(
m
o
d
12
)
-5=7(mod 12)
−5=7(mod12),可见只要确定了模,就可找到一个与负数等价的正数,二者互为补数,且可用该正数来代替该负数,将减法运算用加法实现。
运用在补码当中时,减去一个补码,等于加上这个负补码的补数,将问题转换为求这个负补码的补数,这一运算称为求补,在补码中,求补运算需将所有位(包括符号位)按位取反,再加1.
2.3.2.2整数的补码
2.3.2.3小数的补码
2.3.2.4补码在计算机中的加减法运算
由前文可知,补码作加法时直接按位相加、向高位进位即可,但在作减法运算时需转换为对该数补数的加法运算,而求补的方法就是全部位(包括符号位)按位取反,末位加1.
2.3.2.5补码与无符号数加减运算的对比
1.加法运算
结论:计算机硬件在进行无符号数或补码的加法运算时都是从低位开始,按位相加(符号位参与运算),并向更高位进位。
2.减法运算
结论:计算机硬件在进行无符号数或补码的减法运算时都是被减数不变,减数全部按位取反、末位加1,由减法变加法。
3.总结
在计算机内部的一个数据可以看作是有符号数,也可以看作无符号数,它们的运算实际上是统一的,即计算机并不能区分有符号数与无符号数,而且所做的运算并不需要管你存的是什么数。
2.3.3反码
反码用于作为原码求补或补码求原码的过渡(意思就是没啥用),负数的补码可采用"各位取反,末位加1"的方法得到,若仅各位取反而末位不加1,则就可得到负数的反码表示,因此负数反码的定义就是在相应的补码表示中再末位减1.
正数的原码、反码、补码都相同。
2.3.4移码
当真值用补码表示时,由于符号位与数值位一起编码,故很难从补码的形式上判断真值之间的大小关系,移码就是在真值上加一个常数(称为该移码的偏置值),一般取 2 n 2^{n} 2n(即为符号位上的权值)(机器字长为 n + 1 n+1 n+1),且移码只能用于表示整数,它和补码形式上符号位相反,其余位相同。
2.3.5变形补码
2.3.6总结
2.4运算方法和运算电路
2.4.1一位全加器
A
i
A_i
Ai:加数。
B
i
B_i
Bi:加数。
C
i
−
1
C_{i-1}
Ci−1:低位进位。
C
i
C_i
Ci:向高位进位。
S
i
=
A
i
⊕
B
i
⊕
C
i
S_i=A_i \oplus B_i \oplus C_i
Si=Ai⊕Bi⊕Ci:和位表达式,表示
A
i
、
B
i
、
C
i
A_i、B_i、C_i
Ai、Bi、Ci中有奇数个
1
1
1时,本位和为1,否则为
0
0
0。
C
i
=
A
i
B
i
+
(
A
i
⊕
B
i
)
C
i
−
1
C_i=A_iB_i+(A_i \oplus B_i) C_{i-1}
Ci=AiBi+(Ai⊕Bi)Ci−1:进位表达式。
2.4.2串行加法器
2.4.3串行进位并行加法器
串行进位并行加法器:
n
n
n个全加器相连,每级进位直接依赖于前一级进位,进位信号逐级形成。
进位输出为
C
n
Cn
Cn,位数有限高位自动丢失,实际是模
2
n
2^n
2n的加法运算,最长运算时间由进位信号传递时间决定,位数越多延迟时间越长。
2.4.4并行进位加法器
并行进位加法器:进位信号
C
i
C_i
Ci是同时(并行)产生的。
2.4.5带标志加法器
A L U ALU ALU的核心是带标志加法器,能同时执行算术运算与逻辑运算。
注:
M
U
X
MUX
MUX是多路选择开关,从多个输入信号中选择一个送到输出端,用于决定进行操作的种类。
前面的都是无符号数加法器,只能实现两个无符号数相加减,不能实现有符号数(补码)的加减运算,为此在无符号数加法器的基础上增加相应的逻辑门电路,使得加法器不仅可以计算和/差,还能生成相应的标志信息。
带标志加法器:用于实现带符号整数(补码)之间与无符号整数之间的加减法,sub为0时右侧被打通,
Y
Y
Y不经处理直接作为加数
B
B
B输入,
s
u
b
sub
sub为
1
1
1时左边被打通,
Y
Y
Y按位取反作为加数输入,且由于
s
u
b
sub
sub也会作为最低位
C
i
n
C_{in}
Cin的输入,故相当于按位取反,末位加
1
1
1,符合补码及无符号整数的减法运算。
有符号数和无符号数在计算机中的运算:
上文中提到过,计算机内部并不区分有符号数和无符号数,它们的运算是统一的,在这种情况下,就需要结合标志位来判断不同情况下的运算结果(计算机只负责进行运算,而相关的判断仍由程序完成):
2.4.6溢出判别方法
溢出判断方法:仅当两个同符号数相加或两个异符号数相减才可能产生。
2.4.7定点数的移位运算
移位操作,如 1500 1500 1500相当于 15 15 15相对于小数点左移两位,而对于二进制数而言,在相对于小数点作 n n n位左移或右移时,其实质是该数乘以或除以 2 n 2^n 2n。由于机器数的字长是固定的(寄存器的位数是有限的),故在计算机内部进行左移或右移时会使机器数的高位或低位产生空缺与丢失,丢失可能产生溢出(真值乘 2 2 2后的值不能全部存储在寄存器中)或精度丢失,而空缺时需补 0 0 0或补 1 1 1。
2.4.7.1算术移位
算术移位的对象是有符号数,移位过程中符号位保持不变。
1.原码的算术移位
算术右移:
算术左移:
此处左移时发生了溢出,即真值乘
2
2
2后超出寄存器的表示范围。
原码小数算术移位:
总结:对于原码,算术右移时若舍弃位为
1
1
1,则会丢失精度,算术左移时若舍弃位为
1
1
1,如图中所示,
−
80
-80
−80乘
2
2
2应为
−
160
-160
−160,超出表示范围,则溢出(定点小数同理),且正负数左右移均补
0
0
0。
2.反码的算术移位
正数的反码与原码相同,故精度丢失和溢出的情况与原码相同,而负数反码的
0
0
0相当于原码的
1
1
1,故右移时舍弃位为
0
0
0,则丢失精度,左移时舍弃位为
0
0
0,则溢出(定点小数同理)。
3.补码的算术移位
同理,正数时,左移丢
1
1
1溢出,右移丢
1
1
1精度丢失,负数时,由于左侧同反码,故左移时丢
0
0
0溢出,需在右侧补0(因为右侧同原码);由于右侧同原码,右移丢
1
1
1丢失精度,需在左侧补1(因为左侧同反码)。
例题:若
[
X
补
=
X
0
.
X
1
X
2
.
.
.
X
n
]
[X_补=X_0.X_1X_2...X_n]
[X补=X0.X1X2...Xn],其中
X
0
X_0
X0为符号位,
X
1
X_1
X1为最高数位,若
(
)
()
(),则当补码左移时,将会发生溢出。
A
.
X
0
=
X
1
B
.
X
0
!
=
X
1
C
.
X
1
=
0
D
.
X
1
=
1
A.X_0=X_1 \quad B.X_0!=X_1 \quad C.X_1=0 \quad D.X_1=1
A.X0=X1B.X0!=X1C.X1=0D.X1=1
解析:
当
X
0
=
1
X_0=1
X0=1,即为负数时,由于补码左边相当于反码,故左移丢
0
0
0时会发生溢出,此时
X
0
=
1
,
X
1
=
0
X_0=1,X_1=0
X0=1,X1=0。
当
X
0
=
0
X_0=0
X0=0,即为正数时,补码左移丢
1
1
1发生溢出,此时
X
0
=
0
,
X
1
=
1
X_0=0,X_1=1
X0=0,X1=1。
综上,选
B
B
B。
2.4.7.2逻辑移位
逻辑移位中,将操作数视为无符号数,左移、右移均补0。
2.4.7.3循环移位
不带标志位的循环左移:最高位进入标志位与最低位。
带标志位的循环左移:最高位进入标志位,标志位进入最低位。
不带标志位的循环右移:最低位进入标志位与最高位。
带标志位的循环右移:标志位进入最高位,最低位进入标志位。
2.4.8原码的乘法运算
立个flag,24考研408不考这玩意,跳过了。
ACC与MQ会将内容逻辑右移,将MQ当中已计算的低位1右移丢弃,高位由ACC低位填补,ACC高位补0:
以此类推,得到:
在数值位有n位的情况下只需重复加法操作n次即可。最后需将符号位异或的结果来修改符号位:
所得结果即为乘积的原码值。由此可见,ACC当中实际存储的是乘积的高位,而MQ当中存储的是乘积的低位。且由于每次只有一位参与运算,故称为原码一位乘。
手算的方式(单符号位、双符号位均可):
2.4.9补码的乘法运算
进行计算时,"MQ中最低位"指的是辅助位的前一位。由于MQ增加了辅助位,为保证统一,ACC、X寄存器都会增加一位。其中,乘数(MQ)寄存器当中存储的是单符号位补码,而ACC、X寄存器当中存储的是双符号位补码。
2.5浮点数
2.5.1浮点数的表示
上文提到过,根据小数点的位置是否固定,在计算机中有定点表示和浮点表示两种形式。浮点数表示法就是指以适当的形式将比例因子表示在数据中,让小数点的位置根据需要而浮动,使得在位数有限的情况下扩大的数的表示范围,也保持了数的精度。
2.5.2浮点数的规格化
特点:位数固定,阶码位越多,尾数位越少,表示范围越大,精度越低。阶码的值反映小数点的真实位置,阶码的位数反映浮点数的表示范围,尾数的位数反映浮点数的精度。
注意:此处采用双符号位发生溢出的尾数
01.0100
01.0100
01.0100在参与移位运算时需遵循双符号位的移位规则,即,双符号位的最高位代表真正的符号位,而低位符号位用于参加移位操作以判断是否发生溢出,故在移位时最高符号位
0
0
0保持不动,且右移补
0
0
0。
注:基数不同,浮点数的规格化形式也不同,当浮点数尾数基数为2时,原码规格化数的尾数最高位一定是1,当基数为4时,原码规格化形式的尾数最高两位不全为0.
由于原码是关于原点对称的,故用原码表示的尾数范围也是关于原点对称的。
2.5.3IEEE754标准
I
E
E
E
754
IEEE754
IEEE754标准当中规定常用的浮点数格式有短浮点数(单精度、
f
l
o
a
t
float
float类型)、长浮点数(双精度、
d
o
u
b
l
e
double
double类型)、临时浮点数,其基数隐含为
2
2
2,且尾数采用隐藏位策略的原码表示(因为原码表示的规格化尾数数值最高位一定为
1
1
1,故可隐含)。
阶码全
0
0
0(
f
l
o
a
t
float
float中真值为
0
−
127
=
−
127
0-127=-127
0−127=−127)与全
1
1
1时(
f
l
o
a
t
float
float中真值为
255
−
127
=
128
255-127=128
255−127=128)有其特别的含义:
故阶码真值正常范围为
−
126
∼
127
-126\sim 127
−126∼127。
关于IEEE标准的补充:
- 阶码全为0时:
- 尾数全为0:表示+0或-0(由数符决定)。
- 尾数不全为0:表示非规格化尾数。
- 阶码全为1:
- 尾数全为0:表示正无穷或负无穷(由数符决定)。
- 尾数不全为0:表示浮点数运算出错。
2.5.4定点、浮点数的比较
即,在
I
E
E
E
754
IEEE754
IEEE754标准中,阶码全
1
1
1时(128或1024)当做无穷处理(正/负无穷取决于数符),即当一个正指数超过了
127
或
1023
时
127或1023时
127或1023时,就认为发生了指数上溢并产生异常。
2.5.5浮点数的运算
在浮点数的运算中,阶码与尾数的运算需要分开进行,包括对阶、尾数求和、规格化、舍入、溢出判断共5步。
在计算过程中一般采用双符号位(模
4
4
4补码)参与运算,方便判断溢出的情况,且双符号位能对溢出的情形进行补救。
-
对阶:使两个操作数阶码相同,依据小阶向大阶对齐的原则,阶码小的尾数每右移一位,阶码加1(注意这里是算术右移,最多损失精度而不会发生溢出).
-
尾数求和:按定点数加减法的原则进行尾数求和,且结果不一定规格化,故需规格化处理。
-
规格化:采用双符号位参与运算时,有两种需要进行规格化的情况(由于是模 4 4 4补码,故需按照模 4 4 4补码的原则处理,即尾数部分最高位与符号位相反):
- 尾数上溢:当尾数的符号位为 01 01 01或 10 10 10时表示尾数运算溢出,需要进行右规,将符号位变为 00 00 00或 11 11 11(仍遵循补码的算术右移原则,且符号位最高位为正确的符号位),需右规 1 1 1次。由于右移的过程中最后一位会被移出,故要考虑舍入。
- 尾数下溢:当结果为 00.0 X X X 00.0XXX 00.0XXX或 11.1 X X X 11.1XXX 11.1XXX时,表示尾数下溢,需要进行左规,直到尾数变为 00.1 X X X 00.1XXX 00.1XXX或 11.0 X X X 11.0XXX 11.0XXX(遵循补码规格化的原则).
-
舍入:在对阶或者右规操作时,尾数的低位会移出,影响精度,因此要进行舍入处理。常见的舍入方法有:
- 0 0 0舍 1 1 1入法:若低位最高位是 0 0 0,则直接舍弃,若低位是1,则尾数加 1 1 1。而加 1 1 1可能导致尾数溢出,需再一次右规。
- 恒置 1 1 1法:最低位恒置为 1 1 1。
- 横截断阀:直接截取所需位数,丢弃后面所有位。
-
溢出判断:由于当尾数溢出时会经过右规操作进行修正,故运算结果是否溢出主要看结果的指数是否上溢。当阶码上溢时,产生异常,当阶码下溢时,置为机器数 0 0 0。
有以下几点需注意:
- 算术左规只会出现在尾数规格化的过程中,且每左规一次就会使阶码减 1 1 1,最后根据阶码是否全为0来判断是否指数下溢(当做机器数0处理)。
- 算术右移会出现在对阶、右规格化、舍入(如 0 0 0舍 1 1 1入法)的操作中,在规格化中的右规是由尾数溢出导致的,仅需右规 1 1 1次即可(若是由0舍1入导致尾数溢出而右规,则也只需右规一次即可)。
- 算术右移会导致尾数丢失从而对运算结果进行舍入,即,浮点数的舍入只有对阶、右规格化两种情况。
- 算术右移1次会使阶码加1,需通过判断阶码是否上溢来判断是否运算结果上溢,而上溢可能由右规格化、舍入引起(都设计算术右移),但不会由对阶引起(所对齐的阶本就是正确数据)。
2.6C语言中的类型转换
C语言中的类型转换包括隐式转化与强制转换两种,隐式类型转换是由编译器自动进行的,而显式类型转换是由程序员明确指定的。
隐式转换的规则:
c
h
a
r
−
>
i
n
t
−
>
l
o
n
g
−
>
d
o
u
b
l
e
char->int->long->double
char−>int−>long−>double与
f
l
o
a
t
−
>
d
o
u
b
l
e
float->double
float−>double,注意,
c
h
a
r
char
char视为8位无符号整数。
2.6.1隐式类型转换
在隐式类型转换 c h a r − > i n t − > l o n g − > d o u b l e char->int->long->double char−>int−>long−>double与 f l o a t − > d o u b l e float->double float−>double中,从前到后范围和精度都从小到大,转换过程没有损失( l o n g long long与 i n t int int为32位整数,而 d o u b l e double double尾数共 52 52 52位尾数,加上一位隐含位,共 53 53 53位尾数,故不会损失与溢出)。
2.6.2强制类型转换
强制类型转换是由我们所决定该转换成什么样的类型,通常在转换时会存在存储精度的损失,强制类型转换语法:(强制转换的类型)表达式。
- 有符号数和无符号数之间的转换:解释方式发生改变,字长不同时可能需要零扩展、符号扩展。
- f l o a t float float或 d o u b l e double double转 i n t int int:浮点数转整数时,浮点数的小数部分全部舍去(截断),仅保留整数(精度丢失),且 i n t int int的范围小于 f l o a t float float与 d o u b l e double double,故大数转换时可能溢出。
- i n t int int转 f l o a t float float: i n t int int表示范围小于 f l o a t float float,虽然不会溢出,但是由于 f l o a t float float有效位共 24 24 24位( 23 23 23位尾数加 1 1 1位隐藏位),故当 i n t int int的有效位数大于 24 24 24位时,会进行截断,丢失精度( l o n g long long同理)。
- d o u b l e double double转 f l o a t float float: f l o a t float float范围小(比较阶码即可),故可能会溢出,且 f l o a t float float精度高(比较尾数位数即可),故可能会精度丢失。
2.6.2.1有符号数与无符号数的转换(同字长整数)
规则:位值保持不变,仅改变解释这些位的方式(注意有符号数是补码)。
2.6.2.2不同字长整数之间的转换
当大字长变量向小字长变量强制类型转换时,系统会将多余的高位直接截断,低位直接赋值。
当小字长变量向大字长变量强制类型转换时,若原数字是无符号整数,则进行零扩展,高位补
0
0
0,否则进行符号扩展,高位用符号位进行填充。
int main(){
unsigned short x=65535;
int y=(int)x;
printf("无符号短整型数向有符号整型数强制转换,高位使用0填充:%d \n",y);
short m=-4321;
int n=(int)m;
printf("有符号短整型数向有符号整型数强制转换,高位使用符号填充:%d \n",n);
char a=2;
int b=(int)a;
printf("char是8位无符号整数,向int转换时使用0填充:%d",b);
}
2.6.2.3int转float
i
n
t
int
int表示范围小于
f
l
o
a
t
float
float,虽然不会溢出,但是由于
f
l
o
a
t
float
float有效位共
24
24
24位(
23
23
23位尾数加
1
1
1位隐藏位),故当
i
n
t
int
int的有效位数大于
24
24
24位时,会进行截断,丢失精度(
l
o
n
g
long
long同理)。
举例:
a
=
0000
0001
1111
0101
0100
0011
0010
0001
=
32850721
a=0000\quad 0001\quad 1111\quad 0101\quad 0100\quad 0011\quad 0010\quad 0001=32850721
a=00000001111101010100001100100001=32850721
a
a
a的
25
25
25位到
32
32
32位非零,故发生截断(因为float尾数的有效位数为24位),其转为
I
E
E
E
754
IEEE754
IEEE754标准后的尾数位:
1.1111
0101
0100
0011
0010
000
∗
2
23
1.1111\quad 0101\quad 0100\quad 0011\quad 0010\quad 000*2^{23}
1.11110101010000110010000∗223
故转换后的结果应当为
32850720
32850720
32850720。
int main(){
int a=32850721;
float b=(float)a;
printf("int型变量a=%d,转换为short型变量b后的值为:%f",a,b);
}
2.6.2.4float转int
f l o a t float float转为 i n t int int时,小数部分会被舍去,且可能发生溢出。
2.6.2.5double转float
f
l
o
a
t
float
float范围小(比较阶码即可),故可能会溢出,且
f
l
o
a
t
float
float精度高(比较尾数位数即可),故可能会精度丢失。
验证思想同
i
n
t
int
int转
f
l
o
a
t
float
float,懒得写了。
2.7数据的存储
2.7.1大端方式与小端方式
现代计算机基本采用字节编址,每个地址编号存放1字节数据,不同类型数据占用字节数不同,用最低有效字节(LSB)和最高有效字节(MSB)表示数据的低位和高位。如
32
32
32位计算机中一个
32
32
32位的
i
n
t
int
int变量机器数为
01234567
H
01234567H
01234567H,其最低有效字节
L
S
B
LSB
LSB为
67
H
67H
67H,最高有效字节
M
S
B
MSB
MSB为
01
H
01H
01H。
根据数据中各字节在地址中存储的先后顺序不同,产生了两种存储方式:
大端方式:从最高有效字节到最低有效字节顺序存储元素。
小端方式:从最低有效字节到最高有效字节顺序存储元素。
注意,在阅读小端方式的机器代码时,需要注意字节是按相反顺序显示的,例:
假设小端方式中的语句
i
n
t
i
=
0
;
int \quad i=0;
inti=0;所对应的机器代码为:
C
7
45
F
C
00
00
00
00
C7\quad 45\quad FC\quad 00\quad 00\quad 00\quad 00
C745FC00000000,则语句
i
n
t
i
=
−
64
int \quad i=-64
inti=−64的机器代码为:
C
7
45
F
C
C
0
F
F
F
F
F
F
C7\quad 45\quad FC\quad C0\quad FF\quad FF\quad FF
C745FCC0FFFFFF,因为
−
64
-64
−64所对应的十六进制数(补码)为:
F
F
F
F
F
F
C
0
FF\quad FF\quad FF\quad C0
FFFFFFC0(大端方式与小端方式是数据的存储方式,而与指令字的存储无关)。
2.7.2边界对齐:编址与寻址的区别
2.7.2.1编址
编址方式:即按多大的存储单元分割内存并编址,目前常用的编址方式有字节编址和字编址,大多数计算机采用的是字节编址。
按字编址:一个内存地址对应一个字的信息。
按字编址中的字,指的是机器字长,即计算机进行一次整数运算所能处理的二进制数据的位数,与
C
P
U
CPU
CPU的通用寄存器和
A
L
U
ALU
ALU(运算逻辑单元)的位数一致。
常说的,数据总线的宽度与机器字长一致,并不准确,数据总线细分又分外部数据总线和内部数据总线,处理器在设计时一般通用寄存器
G
P
R
s
GPRs
GPRs和运算器及内部数据总线是一致的,外部数据总线反应的是
C
P
U
CPU
CPU和内存之间的数据传送能力,两者不一定一致,常说的数据通路带宽指的是外部数据总线的宽度,它与
C
P
U
CPU
CPU内部的数据总线宽度(机器字长宽度)可能不同。
按字节编址:一个内存地址对应一个字节的信息。
以字长为
32
32
32位为例:
例:某计算机字长为
32
32
32位,其存储容量为
64
M
B
64MB
64MB,它的寻址范围是多少?需要多少根地址线?按字节编址呢?
答:按字编址时,字长为
32
32
32位=
4
B
4B
4B,存储容量为
64
M
B
64MB
64MB,故存储单元数为
16
M
16M
16M,故寻址范围为
0
∼
2
24
−
1
0\sim 2^{24}-1
0∼224−1,需要
24
24
24根地址线。
按字节编址时,存储单元数为
64
M
64M
64M,故寻址范围为
0
∼
2
26
−
1
0\sim 2^{26}-1
0∼226−1,需要
26
26
26根地址线。
个人理解:现代计算机按字节编址,可支持按字寻址的含义在于,按字节寻址时地址码为26位,而按字寻址时虽然也是26位,但其中前24位是真正的字地址,后2位则是字内地址(因为是按字节编址,所以需要精确到字节)。此时MAR为26位,但如果是按字编址,MAR只需24位即可访问到所有
2.7.2.2寻址与地址转换
这里说的寻址不是指令集设计里的什么立即数寻址、寄存器寻址、直接寻址、间接寻址等等,这些寻址方式是解释怎么由指令封装中的形式地址得到内存有效地址(
E
A
EA
EA)的方法。而这里说的寻址是强调通过给定地址怎么得到相应数据,,更准确说是信息,因为程序和数据在内存中是没区别的,都是
0
、
1
0、1
0、1信息。
现代计算机基本支持按字、半字寻址,由于是按字节编址(一个地址包含1B的数据量),即
0
0
0号地址代表
0
0
0号字节,
1
1
1号地址代表
1
1
1号字节,按字节寻址时,即为去寻找第
n
n
n号字节时,
n
n
n数值上等于地址编号(因为是按字节编址),而按字寻址时,即表示去寻找第n号字,但由于是按字节编址,此时
n
n
n就需要转换为相应的字节地址,按半字寻址同理。
不同寻址方式的地址转化:以机器字长为32位为例,此时一个字包含4个字节,当按字寻址时,只需要将对应字的编号算术左移两位即可转换为对应的字节起始地址。如这里要读取1号字,只需将1算术左移两位得到100,即可获得该字起始字节的地址,半字、双字的地址转换同理。
寻址范围计算的举例:一个主存的地址线为24根,计算机器字长为32位,按字节编址,探讨按字节与按字寻址时的寻址范围。
由地址线数目可知,其地址为24位,又因为是按字节编址,即有
2
24
2^{24}
224个存储单元进行编址,且每个存储单元包含1字节的数据,共有
2
24
2^{24}
224个字节。
按字节寻址时,由于有
2
24
2^{24}
224个字节,故可寻址范围即为:
2
24
=
16
M
2^{24}=16M
224=16M
按字寻址,由于一个字包含4个字节,故有
2
24
÷
4
=
2
22
2^{24}÷4=2^{22}
224÷4=222个字,故可寻址范围为:
2
22
=
4
M
2^{22}=4M
222=4M
由于地址线为24根,按字寻址时,地址的前22位表示字地址,后2位则用于区分该字中不同的字节(一个字包含4个字节)。在计算时,若要访问
(
2
)
10
=
(
10
)
2
(2)_{10}=(10)_2
(2)10=(10)2号字,只需将其逻辑左移2位,
(
1000
)
2
=
(
8
)
10
{(1000)_2=(8)_{10}}
(1000)2=(8)10,即可得到对应的起始字节地址。
相应地,按半字寻址需逻辑左移1位(可理解为由于半字包含2个字节,故用一根地址线即可区分半字中包含的两个字节),双字需逻辑左移3位。
2.7.2.3数据对齐
假设存储字长为
32
32
32位,可按字节、半字和字寻址(即可一次读取某个字节、字、半字的数据),当数据以边界对齐的方式进行存储时,半字地址一定是
2
2
2的整数倍,字地址一定是
4
4
4的整数倍,这样无论所取的数据是字节、半字、还是字均可一次访存取出。举例:
依次放入
i
n
t
、
s
h
o
r
t
、
d
o
u
b
l
e
、
c
h
a
r
、
s
h
o
r
t
int、short、double、char、short
int、short、double、char、short类型的变量,
i
n
t
int
int是
32
32
32位即
4
B
4B
4B,故起始地址需要是
4
4
4的整数倍(此处是按字节编址),占4B空间,short为
2
B
2B
2B,故起始地址需要是
2
2
2的整数倍,占
2
B
2B
2B空间,
d
o
u
b
l
e
double
double是
8
B
8B
8B,故起始地址为08H,故起始地址需要是
8
8
8的整数倍,占
8
B
8B
8B空间,
c
h
a
r
char
char是
1
B
1B
1B,故起始地址任意,占
1
B
1B
1B空间。当所存储的数据之间有间隙时,可填补空白字节。
在边界对齐的方式中,虽使用空白字节进行填补浪费存储空间,但可提高取指令和取数的速度,表现在无论所取的数据是字节、半字还是字(即按字节、半字还是字寻址),如按半字寻址时想要取出
2
=
(
010
)
2
2=(010)_2
2=(010)2号半字的数据(即图中第一个
s
h
o
r
t
short
short变量),只需左移
1
1
1位即可得到其地址
(
0100
)
2
=
4
(0100)_2=4
(0100)2=4,且一次就可全部取出。
若不采用数据对齐的方式进行存储,如该
s
h
o
r
t
short
short数据存储在地址
03
H
03H
03H与
04
H
04H
04H的存储单元当中,则由于半字寻址时只能访问起始地址为
02
H
、
04
H
02H、04H
02H、04H的存储单元(一次取出一个半字的数据),故需要两次访存操作,影响指令执行顺序。
在
R
I
S
C
RISC
RISC指令集中,通常采用边界对齐方式 ,能更好适应指令流水线。
2.6王道课后题详解
本章王道课后题较难,但学会补码的求补原理后实际是很简单的,有空再写了。
三、存储系统
前言1:半导体元器件及其原理
以RAM芯片的存储元——MOS管为例。
MOS管可视为一种电控开关,输入电压到达某个阈值时,如5V,MOS就可接通导电。由于电容下端接地为0V,当MOS管上端接通后会产生电压差而保存电荷,这种状态用于表示二进制信息1。读取数据时,将MOS管端口接入5V电压,此时电容上端的电荷就会向外流通,外部检测到电流,从而认为保存二进制信息1。
将存放一个二进制位的物理元器件称为存储元,计算机编址时按存储单元编址(一般包含8个存储元),即将地址码相同的多个存储元构成一个存储单元。
读取一个存储单元的过程如下:
当给红色线加5V电平时,所有MOS管都会被导通,从而使得电荷会向外导出,故而,一次可从一个存储单元中读出一个存储字,本例中,存储字长即为8bit。故称存储器每一次读或写的单位都是读或写一个存储字(一个存储字可是多个字节,现代计算机基本按字节编址,一个存储字长为1B,即包含8个存储元件,在读取一个存储单元时会同时读出这八位数据)。
这里给出了存储器的简单模型(8×8位存储芯片)。
译码驱动:包括地址译码器和驱动器,驱动器可使译码器发出的字选信号稳定有效,相当于对信号的加强,地址译码器则用于将地址转换为译码输出线上的高电平,以便驱动相应的I/O电路读写数据。
I/O电路:用于控制被选中单元的读出或写入。
片选线:一个存储器往往包含多个芯片(一个芯片包含多个存储单元),在访问某个字时,必须选中该存储字所在的芯片,而其他芯片不被选中,故需要有片选控制信号。
读写控制线:根据CPU给出的命令控制被选单元进行读或写。
设地址总线为3根,即MAR大小为3位,则这3位二进制数有
2
3
=
8
2^3=8
23=8种不同的组合,经过译码器后可产生8种不同的输出信号,经过8根译码器字选线后可连接到8个存储单元。
当译码器字选线被接通后,就会将相应存储单元存储的数据(实际是电压状态)通过数据线送入MDR当中,从而读取了该存储单元的数据,之后CPU就可通过数据总线从MDR中读取数据,其中,控制逻辑起协调作用,如只有当MAR中的信号稳定后才接通译码器。
注意:片选线、读/写线符号上的一横表示低电平有效,且读写控制线可进行合并,两种方案下芯片对外暴露的引脚数不同,这是常见考点。
注意:引脚数目包含地址线、数据线、片选线、读写控制线。
前言2:寻址
编址:现代计算机一般按字节编址,即图中一个小方格(存储单元)包含一个字节的数据,也对应一个地址,当有1k个地址/存储单元时,相应地址线共有10根。
寻址:现代计算机基本支持按字、半字寻址,由于是按字节编址(一个地址包含1B的数据量),即0号地址代表0号字节,1号地址代表1号字节,按字节寻址时,即为去寻找第n号字节时,n数值上等于地址编号(因为是按字节编址),而按字寻址时,即表示去寻找第n号字,但由于是按字节编址,此时n就需要转换为相应的字节地址,按半字寻址同理。
不同寻址方式的地址转化:以机器字长为32位为例,此时一个字包含4个字节,当按字寻址时,只需要将对应字的编号算术左移两位即可转换为对应的字节起始地址。如这里要读取1号字,只需将1算术左移两位得到100,即可获得该字起始字节的地址,半字、双字的地址转换同理。
寻址范围计算的举例:一个主存的地址线为24根,计算机器字长为32位,按字节编址,探讨按字节与按字寻址时的寻址范围。
由地址线数目可知,其地址为24位,又因为是按字节编址,即有
2
24
2^{24}
224个存储单元进行编址,且每个存储单元包含1字节的数据,共有
2
24
2^{24}
224个字节。
按字节寻址时,由于有
2
24
2^{24}
224个字节,故可寻址范围即为:
2
24
=
16
M
2^{24}=16M
224=16M
按字寻址,由于一个字包含4个字节,故有
2
24
÷
4
=
2
22
2^{24}÷4=2^{22}
224÷4=222个字,故可寻址范围为:
2
22
=
4
M
2^{22}=4M
222=4M
由于地址线为24根,按字寻址时,地址的前22位表示字地址,后2位则用于区分该字中不同的字节(一个字包含4个字节)。在计算时,若要访问
(
2
)
10
=
(
10
)
2
(2)_{10}=(10)_2
(2)10=(10)2号字,只需将其逻辑左移2位,
(
1000
)
2
=
(
8
)
10
{(1000)_2=(8)_{10}}
(1000)2=(8)10,即可得到对应的起始字节地址。
相应地,按半字寻址需逻辑左移1位(可理解为由于半字包含2个字节,故用一根地址线即可区分半字中包含的两个字节),双字需逻辑左移3位。
前言3:常用逻辑门符号
3.1存储器概述
给出框架,按书背即可。
注意:在Cache-主存层和主存-辅存层中,上一层的内容都只是下一层中的内容的副本,也即Cache(或主存)中的内容只是主存(或辅存)中的内容的一部分。
3.2主存储器
3.2.1ROM芯片与RAM芯片
3.2.1.1RAM芯片
a.SRAM
静态随机存储器SRAM,存储元是双稳态触发器(六晶体管MOS),只要不断电,触发器的状态就不会改变,因此即使信息被读出,也不需要再生(非破坏性读出)。
b.DRAM
动态随机存储器DRAM,存储元是单个晶体管,原理是栅极电容电荷存储信息,故集成密度高,电容内电荷只能维持2ms,即使不断电,2ms后信息也会丢失,故需每隔一定时间需刷新,一般取2ms,称为刷新周期,其中一共有三种刷新方式。
在介绍刷新方式之间,先介绍DRAM的刷新特点:以行为单位的刷新。
注意:存储器的刷新和存储器的恢复是不一样的概念,SRAM和DRAM存取周期都包含恢复时间(恢复内部状态,才能进行下一次存取),而DRAM还需要定期刷新。
在本节前言中介绍的是存储器的简单模型(左图),在简单模型当中,一个译码器需要处理
2
n
2^n
2n根选通线,不利于电路设计,事实上可将存储单元进行二维排列,将原先地址分为行地址与列地址,并分别使用行地址译码器与列地址译码器,使得每个译码器只需处理
2
n
/
2
2^{n/2}
2n/2根选通线。故而在硬件支持下,可一次性刷新一整行的存储单元,且刷新操作与读写操作类似,其占用一个读写/访存周期。
下面假设DRAM内部结构排列成128×128的形式(有128行,每行有128个存储单元),读/写周期(存取周期)0.5us,刷新周期为0.2ms。即刷新周期为4000个存取周期。
注意:
分散刷新方式
每一次读写完都刷新一行,芯片的存取周期为0.5us,则系统存取周期变为1us,前0.5us用于正常读写,后0.5us用于刷新某行(不一定是读/写的行),此时2ms内有2000个存取周期(可刷新2000行),故一定可在刷新周期内刷新完所有行。
特点:没有死区,但存取周期变长,整机速度下降。
集中刷新
2ms内集中安排时间全部刷新,系统存取周期仍为0.5us,则2ms包含的4000个存取周期内,前3872个周期可正常读写,后128个周期专门用于刷新,这段时间无法访问存储器,称为访存"死区",死区率为128/4000=3.2%。
特点:读写操作时不受刷新影响,但集中刷新期间不能访问存储器。
异步刷新
2ms内每行刷新一次即可,即2ms内产生128次刷新请求,每隔2/128=15.6us刷新一次,即每15.6us内有0.5us的死时间。
特点:使CPU避免连续等待过长时间,也减少了刷新次数。
DRAM刷新的特点:
c.SRAM与DRAM的总结
DRAM的容量较大,地址线数目较多,故采用地址线复用技术,第一次将行地址送入行地址缓冲器(
n
/
2
n/2
n/2位),第二次将列地址送入列地址缓冲器(
n
/
2
n/2
n/2),使得只需要
n
/
2
n/2
n/2根地址线。之后由时序逻辑控制将二者送入行、列地址译码器。
需要注意的是,在采用地址复用技术时,地址线减半,但会多增加行通选线和列通选线(片选线用行通选代替)
以下内容取自https://blog.csdn.net/weixin_45415929/article/details/124993133
上图是一个DRAM芯片,共有 2 6 = 64 2^{6}=64 26=64个存储单元,故不采用地址复用技术时需要6根地址线,而采用地址复用技术时需使用3根地址线,一根行通选(RAS)和一根列通选(CAS)线,当RAS高电平时,表示当前输入的是行地址,CAS高电平,表示当前输入的是列地址,这两根线的存在代替了片选线。
3.2.1.2ROM芯片
计算机内的重要ROM:计算机的主存由RAM和ROM共同构成。事实上,主板上的BIOS(ROM)芯片存储了自举装入程序,使得通电后CPU能根据这段程序去辅存中读出操作系统并执行。虽然BIOS位于主板上,但逻辑上主存由RAM和ROM共同组成,统一编址。
3.2.2主存储器的基本组成
3.2.3多模块存储器
DRAM芯片的恢复时间比较长,可能是存取时间的几倍(SRAM恢复时间较短),为避免恢复时间过长而引起CPU效率降低,而引出双端口RAM、多模块存储器。
3.2.3.1 双端口RAM
3.2.3.2多模块存储器
多模块存储器是一种空间并行技术,利用多个结构完全相同的存储模块的并行工作来提高存储器的吞吐量,常见的有单体单体多字存储器、多体低位交叉存储器
a.多体并行存储器
这里设存取周期为T,存取时间为r,即一次读写操作完成后需要3r的恢复时间(恢复时间内整个存储体都不可访问)。
在高位交叉编址中先根据高位体号确定模块,再在模块内访问存储单元。当访问一组连续地址时,实际就是对其中一个模块的多次访问(单模块内地址单元连续),故存取方式仍是串行存取(一次读写后必须等待恢复时间之后才能进行下一次读写),故而仍是顺序存储器,并不能提高存储器吞吐量。
低位交叉编码的方式下,先根据低位体号确定模块,再根据高位地址来存取数。当访问一组连续地址时,使得完成一次读写后,不必等待恢复时间即可立即读取下一个存储字,从而再不改变每个模块存取周期的前提下,采用流水线的方式并行存取(宏观并行,微观串行)(n->无穷时,读写一个字的时间接近存取时间),使用存储器带宽提高。
以上是低位交叉编址模块数目的确定,此处总线传送周期是指通过数据总线将数据传给CPU至少需要r的时间,无论是哪种表示方式,都意味着CPU存取一个数据的时间不可能低于r。
若给定一个地址x,确定它属于第几个存储体:若x是二进制,则直接取低位进行判断即可,若x是十进制,则对m取余即可。
b.单体多字存储器
在一个存取周期内,从同一地址取出m条指令,然后将指令逐条送至CPU执行,即每隔1/m存取周期,CPU向主存取一条指令,提高单体存储器的工作速度(若T=4r,m=4,则它和低位交叉编址的多体并行存储器工作速度基本一致),缺点是指令和数据在主存中必须连续存放,一旦遇到转移指令,或操作数不能连续存放,则效果不明显。
3.3主存储器与CPU的连接
由于现代计算机MDR与MAR是集成在CPU当中的,故而主存存储器通过数据总线、地址总线和控制总线与CPU连接。
其中,数据总线的位数与工作频率的乘积正比于数据传输速率,地址总线的位数决定可寻址的最大内存空间,控制总线(读/写)指出总线周期的类型和本次输入/输出的完成时间。
3.3.1位扩展:增加存储字长
当CPU数据线数与存储芯片数据位数不同时,需对存储芯片进行位扩展。
特点:各芯片连接地址线方式相同,但连接数据线的方式不同,在某一时刻选中所有芯片,故片选信号要连接到所有芯片。
当CPU发送地址信号时,由于地址信号与两个芯片的连接方式相同,故选中的是两个芯片相同位置处的存储单元,而读出的数据依次作为不同数据位,由此实现位扩展。
此处8片
8
k
×
1
8k×1
8k×1位的存储芯片扩展为1个
8
k
×
8
8k×8
8k×8位的存储器,容量为8KB。
3.3.2字扩展:增加存储字数
线选法
线选法将多出的地址位作为线选信号来对存储芯片进行选择,当对应地址位为1时,表示选择了相应的芯片。这种方法下,多出n位地址最多产生n个片选信号,即最多连接n个芯片(因为最多只能有一个是高电平,否则出现多个芯片同时被选择的情况)。
注意:此处芯片上的
C
S
CS
CS表示是高电平有效,若是低电平有效,则两个芯片的合法地址范围互换。
图中分别给出了左右两个芯片的合法地址范围。
也可使用非门,使得仅需
A
13
A_{13}
A13一位地址线就可实现对两个芯片的控制,此时的非门相当于是一个1-2译码器,即1个输入可得到两种不同的状态。
译码器片选法
此时n位地址码可输出 2 n 2^n 2n种不同的片选信号,即多出n位地址时,可同时连接 2 n 2^{n} 2n个芯片。
总结
3.3.3字位同时扩展:增加存储字长与存储字数
3.3.4存储芯片的选择
通常选用ROM存放系统程序、标准子程序和各类常数,RAM则是为用户编程而设置。
3.3.5补充:译码器
译码器与存储芯片应当是配套使用的,输出不取反的译码器(左侧),其输出电平为高电平,应与高电平有效的芯片配合使用,而输出取反的译码器(右侧),其输出电平为低电平,应与右侧低电平有效的芯片配合使用。
译码器往往还有使能端
E
N
EN
EN,类似于
C
S
CS
CS片选信号,接通后使得译码器可正常工作。
也有的译码器有多个使能端,只有三个都是有效电平时才能使译码器正常工作,需要注意是高电平还是低电平有效。
下面是3-8译码器的真值表:
3.4外部存储器
3.4.1磁盘存储器
磁盘存储器的组成
磁盘控制器:接收主机发来的命令,转换为磁盘驱动器控制信号,实现主机和驱动器间数据格式的转换和数据传送。
磁盘驱动器:接收磁盘控制器传来的命令信息,并寻找目标磁道进行读写。
每个盘片(记录面)都有一个磁头与之对应,用于获取该盘片的数据,而每个盘面都会被划分为若干磁道(同心圆),将多个盘片相同位置的磁道称为一个柱面,柱面数即为每一盘片上的磁道数。
侧面图:
磁盘存储器的性能指标
注意,磁盘的非格式化容量一般大于格式化容量。
传输数据的过程实质就是扇区在磁头下划过的过程。
注意:
- 磁盘是以扇区为单位进行读写数据,且由于寻道和找扇区的距离远近不一,故寻道时间(题目会给)和旋转延迟时间(一般取磁盘转半圈的时间)一般取均值,而传输时间即为转过一个扇区所花费的时间,当题目中给出转速后,即可算出旋转延迟时间与传输时间。
- 有的题目还会给出磁盘控制器延迟,即磁盘驱动器接收命令并发出信号的时间。
磁盘转一圈相当于读取了一个磁道上的所有数据,
r
r
r转/秒相当于1秒转了
r
r
r圈,故若每条磁道容量为
N
N
N个字节,则数据传输率为
D
r
=
r
N
D_r=rN
Dr=rN。
磁盘地址与工作过程
3.4.2磁盘阵列
3.4.3固态硬盘
当系统对磁盘进行读写时,一个逻辑块对应磁盘的一个块/扇区(磁盘以扇区为读写单位),而对SSD的读写以页为单位,每次读/写一个页,而非块,即固态硬盘的一个页相当于磁盘的一个扇区,而此时固态硬盘的一个块就相当于磁盘的一个磁道。
3.5高速缓冲存储器
3.5.1程序访问的局部性原理
3.5.2Cache的基本工作原理
总结:在上述理论基础上,可以理解出,Cache利用了局部性原理(包含空间与时间,空间体现在之后访问的字大概率也在该块中,之后就不需要再访问主存,时间体现在之后再访问这个字也无需再访问主存)(因为当CPU要读取一个字时,该字及其附近的字会作为一个块调入Cache当中)。
注:PDF这里有点问题,Cache行这一概念所对应的主存块与操作系统中分页系统中页面的概念并不一致(英译汉的原因),一般地,Cache行的大小小于页面大小。
3.5.3Cache和主存的映射方式
事实上,Cache每一行的地址结构为:
- 有效位:标记Cache行中存储的数据是否有效,初始阶段Cache块应是"空"的,其中内容并无意义,有效位全为0.
- 脏位:也称一致性维护位,和Cache数据一致性维护方式有关。
- 替换算法控制位:与替换算法有关。
3.5.3.1全相连映射
在全相连映射方式中,主存中的每一块都可装入Cache中的任何位置,而Cache每行的标记用于指出该行取出主存的哪一块。
全相连映射方式中的标记号实际就是主存块号,采用全相连映射方式时,主存的地址结构可划分为:
- 优点:灵活。
- 缺点:标记比较速度较慢,实现成本较高,通常需要采用昂贵的按内容寻址的相联存储器进行地质映射。
相连存储器:即可按地址寻址也可按内容寻址(内容的某些字段),又称按内容寻址的存储器,其存储的每个字由若干字段组成,每个字段描述了对象的一个属性,每次查找是将所有存储字的相关字段与检索项同时进行比较。
3.5.3.2直接映射方式
上图中,在直接映射方式下,若开始时0号主存块存放在了0号Cache行中,此时若8号主存块被调入Cache,则即使其他Cache行仍空缺,0号Cache中存储的0号主存块内容也会被无条件替换(不涉及替换算法),这也导致Cache中其他许多地址空着也不能被使用。
事实上,对于计算机而言,可直接利用主存块号的末尾三位(本例Cache行有8个)来获得主存块在Cache行中应当存放的位置(如0号块与8号块的末尾三位都是0,它们也都存放在第0行Cache中),故而这三位不作为Cache行的标记信息,而仅使用前19位作为Cache的标记信息:
完整的CPU访存过程为:
- 优点:实现简单。
- 缺点:不够灵活,即使Cache的其他许多地址空着也不能占用,这使得映射的块冲突率最高,空间利用率最低。
3.5.3.3组相连映射方式
组相连映射方式的计算方法与直接相连映射方式的计算方法类似,利用取余运算(即根据主存块号末位进行判断)即可获取主存块对应的组号,也因此,主存块号对应的末尾并不参与构成Cache的标记号。
此时主存地址结构被划分为:
完整的CPU访存过程为:
特点:路数越大,即每组Cache行的数量越大,发生块冲突的概率越低,但相连比较电路也越复杂,选定适当的数量,可使组相连映射的成本接近直接映射,而性能上接近全相连映射。
3.5.3.4总结与例题
3.5.4Cache中主存块的替换算法
3.5.4.1随机算法RAND
3.5.4.2先进先出算法FIFO
3.5.4.3近期最少使用算法LRU
在王道课本上给的是以组相连映射为例:
注意:在采用全相连与组相连方式下替换算法标志位位数是不同的。
3.5.4.4最近不经常使用算法LFU
当计数器值相同时,即可按计数器值递增的顺序,也可按先进先出的顺序进行替换。
3.5.4.5总结
3.5.5Cache写策略
由于Cache中存储的是主存块副本,当对Cache中的内容进行更新时,就需要使用相关写操作策略使Cache内容和主存内容保持一致,分为写命中和写不命中两种情况。
命中:要修改的单元在Cache中。
3.5.5.1写命中
写回法
每个Cache行设置一个修改位(脏位),若修改位为1,则说明对应Cache行中的块被修改过,替换时需要写回主存;若修改位为0,则说明对应Cache行中的块未被修改过,替换时无需写回主存。
全写法
写缓存:为减少全写法直接写入主存的时间损耗,Cache和主存之间有写缓存,CPU可同时将数据写到Cache和写缓存中,再由写缓存控制将内容写回主存(避免CPU直接写入主存而带来的时间损耗,因为CPU写入主存的速度远慢于写入Cache)。
3.5.5.2写不命中
写不命中是指要修改的单元不在Cache中的情况。
写分配法
非写分配法
3.5.5.3多级Cache
3.5.6例题
k从0开始增加到999,操作对象是数组,存储的地址空间连续,由于int型数据占4B,故一个Cache块中可存放4个int型数据。
首先读出a[0]中的数据,由于初始时Cache缺失,故需将该主存块写入第一行Cache中,此时a[0]、a[1]、a[2]、a[3]的数据一并被写入。
故而,在第一个Cache块中只有第一个字节的数据(a[0])在读入时发生Cache缺失而写入时并不缺失,对于该块中所有数据而言,一共访问了8次,但只发生一次Cache缺失。
当Cache写满后,即读取a[132](a[0]对应第1块,a[4]对应第二块,a[8]对应第三块,a[12]对应第四块,以此类推,第64块对应a[132]),此时出现置换,但Cache缺失率仍为1/8.
综上,Cache缺失率为1/8。
3.6虚拟存储器
前言:页式存储管理
在用户编程视角使用的实际是逻辑地址(虚地址),上图中以取数指令为例(取变量x至ACC寄存器中):
000001
000001
000001
001000000011
001000000011
001000000011(操作码+地址码)
其中可将逻辑地址进行划分,划分为:
逻辑页号 | 页内地址 |
---|---|
若干位 | 页内地址 |
对于变量x,可将其逻辑地址地址结构进行划分从而判断出x属于0号页面,再将x的页内地址(块内地址)拼接其主存块号从而得到真实物理地址,为完成逻辑页号到主存块号的映射,操作系统建立了一张页表:
将页表中的一行称为一个页表项,一个页表项对应一个页号和主存块号的映射关系,地址变换过程如下:
页表基址寄存器存放进程的页表首地址,可根据虚拟地址高位部分的虚拟页号找到对应的页表项并获得对应的主存块号,将其与虚拟地址低位部分的页内地址进行拼接,从而得到实际物理地址。
事实上,可将近期访问的页表项放入更高速的存储器,可加快地址变换的速度,基于这个思想而引入了另一种高速缓冲存储器——快表(TLB),相应地,将放在主存中的页表称为慢表,在地址转换时,先查找TLB,若命中,则无需访问主存的页表。
上图中的地址码为
001000000011
001000000011
001000000011,对应的逻辑页号为
00
00
00,若在快表中查找不到对应的页表项,CPU才会去主存中查询慢表,在得到主存块号后,与逻辑地址拼接,即可得到最终的物理地址。且会将慢表中的该页表项放入快表当中,使得若接下来的指令仍要访问0号逻辑页面,则CPU可迅速从快表中找到零号逻辑页所对应的主存块号。
需要注意的是,快表是在得到物理地址的过程中起到加速作用,而Cache是在实际访问主存的过程中起到的加速作用。
事实上,快表由SRAM制成(一种特殊的高速缓冲存储器),是一种相联存储器,可按内容寻址,即可根据标记的内容快速判断是否有相应数据。
3.6.1虚拟存储器的基本概念
3.6.2页式虚拟存储器
页式存储管理是将程序在逻辑上分页,主存分块,块的大小和页的大小相等,每块装入一页,用户程 序在执行前全部装人主存。 而页式虚拟存储管理在分页和分块上同页式存储管理,所不同的是页式虚拟存储管理不要求将程序全部装入主存即可投入运行。 即页式要求全部装入,而页式虚拟管理只是部分装入,然后采用部分替换技术。
在程序运行过程中,可将需要运行的#0和#1的页面放入主存的相应位置,而其余页面先放在外存当中,为此将之前的页表进行改造,增加有效位,当其为1时表示已调入内存,当需要从内容调入这些页面时,可根据外存块号将其调入(辅存块的大小一般与主存块大小相同)。访问位可用于实现页面替换算法,其记录最近一段时间内页面被访问的次数,脏位则记录该页是否被修改。
具有TLB和Cache的多级存储系统
3.6.3段式虚拟存储器
3.6.4段页式虚拟存储器
3.7本章小结
四、指令系统
4.1指令的基本格式
以下讨论的地址格式均为主存地址,但实际地址字段亦可能是寄存器编号等,此时无需访存,而是直接访问寄存器,提供运行速度。
4.1.1基本指令格式
1)零地址指令
2)一地址指令
对于:
O
P
(
A
1
)
−
>
A
1
OP(A_1)->A_1
OP(A1)−>A1
若地址字段为主存地址,则需访存3次(取指令1次,取操作数1次,写操作1次)。
对于:
(
A
C
C
)
O
P
(
A
1
)
−
>
A
C
C
(ACC)OP(A_1)->ACC
(ACC)OP(A1)−>ACC
若地址字段为主存地址,则需访存2次(取指令1次,取操作数1次)。
3)二地址指令
对于:
(
A
1
)
O
P
(
A
2
)
−
>
A
1
(A_1)OP(A_2)->A_1
(A1)OP(A2)−>A1
若地址字段为主存地址,则需访存4次(取指令1次,取操作数2次,写操作1次)。
4)三地址指令
5)四地址指令
4.1.2扩展操作码指令格式
定长指令字结构
+
可变长操作吗
=
》扩展操作码指令字结构
(
不同地址数的指令使用不同长度的操作码
)
定长指令字结构+可变长操作吗=》扩展操作码指令字结构(不同地址数的指令使用不同长度的操作码)
定长指令字结构+可变长操作吗=》扩展操作码指令字结构(不同地址数的指令使用不同长度的操作码)
4.1.3指令的操作类型
JMP指令:无条件的转移到指令指定的地址去执行从该地址开始的命令。
调入指令CALL与返回指令RETURN:调入指令CALL一般与返回指令RETURN配合使用,前者用于从当前程序位置转入子程序入口(如系统调用、过程调用),后者则用于子程序执行完成返回原程序断点,每个CALL都对应一条RETURN。
陷阱与陷阱指令:陷阱是一种意外事故的中断,如除数为0、算术溢出、特权指令等使计算机不能正常工作的意外事件,此时计算机会发出陷阱信号,暂停当前指令的执行,转入故障处理程序。一般不提供给用户直接使用,出现意外时计算机自动执行。也有的及其设置供用户使用的陷阱指令或访管命令,利用它完成系统调用或程序请求。
4.2指令的寻址方式
4.2.1指令寻址
指令寻址:寻找下一条欲执行指令的地址。
顺序寻址
定长指令字结构+指令字长等于存储字长+主存按字编址
在最基本的情况中,两条指令的地址刚好相差1,每执行完一条指令后,PC的值会自动加1(此处主存按字编址,1表示一个存储字长)。
定长指令字结构+指令字长等于存储字长+主存按字节编址
此时,两条指令的地址刚好相差2(因为是按字节编址),每执行完一条指令后,PC的值会自动加2(相当于1个指令字长的大小)。
变长指令字结构+指令字长等于存储字长+主存按字节编址
此时,两条指令的地址偏移量并不确定,每执行完一条指令后,PC根据操作码类型的值会自动加n(相当于1个指令字长的大小)。
跳跃寻址
假设系统采用定长指令字结构,指令字长=存储字长=2B,主存按字编址,
JMP:无条件转移指令。
当CPU执行到:
J
M
P
7
JMP\quad7
JMP7
时,会将PC的值改为7,下一条将执行的指令即为:
L
D
A
1100
LDA\quad1100
LDA1100
4.2.2数据寻址
数据寻址:确定本条指令的地址码指明的真实地址。
寻址特征用于指出数据寻址的方式,且以下例子皆为一地址指令。
直接寻址
间接寻址
图中所给的两次间址方式为,当主存字第一位为1时,表示取出的仍不是操作数的地址,即多次间址;主存第一位为0时,表示取得的是操作数的地址。
间接寻址对操作树寻址范围的扩展:由于A的位数一般小于指令字长,而存储字长可与指令字长相等若设指令字长和存储字长均为16位,A为8位,显然直接寻址范围为
2
8
2^8
28,一次间接寻址的范围可达
2
16
2^{16}
216,当多次间接寻址时,可利用存储字首位表示寻址是否结束,但不能作为
E
A
EA
EA的组成部分,此时其寻址范围为
2
15
2^{15}
215。
间接寻址便于编制程序:
图中表示两次调用子程序,只要在调用前先将返回地址存入子程序最末条指令的形式地址A的存储单元中,便可准确返回到原程序断点。如第一次调用前使
[
A
]
[A]
[A]=81,第二次调用前使
[
A
]
[A]
[A]=202。
由于间接寻址及多次间接寻址的访问速度过慢,并不常用,故一般问道扩大寻址范围时,指的是寄存器间接寻址。
寄存器寻址
寄存器间接寻址
隐含寻址
如:
(
A
C
C
)
O
P
(
A
1
)
−
>
A
C
C
(ACC)OP(A_1)->ACC
(ACC)OP(A1)−>ACC
这种地址的指令格式不明显地在地址字段中指出第二操作数的地址,而规定累加器ACC作为第二操作数的地址,指令格式明显指出的仅是第一操作数的地址,因此,ACC对单指令格式来说是隐含寻址。
以下是三大偏移寻址(以某个地址作为起点,形式地址视为偏移量)
基址寻址
以程序的起始存放地址作为起点。
事实上,可由操作系统或管理程序根据主存使用情况赋予
B
R
BR
BR一个初值(基址),可用于将用户逻辑地址转化为主存的物理地址,将用户程序安置在主存某一空间。
程序浮动:在多道程序设计系统中,要求编制的程序放在主存的任何区域都能正确执行,即使在执行过程中程序改变了位置,其仍不受影响。例:
当程序在主存中的位置发生改变时,操作系统只需修改BR寄存器中的内容,使之指向当前程序的起始地址即可,避免了对原程序的修改。
变址寻址
程序员自己决定从哪里作起点。
第一条指令表示将立即数0存放到累加寄存器ACC当中,实现循环中的十次加法操作,一共使用了十条加法指令,最后再将累加寄存器ACC中的值存放到sum变量当中。
这种编写方式极其不方便,可引入变址寻址简化程序的编写,仅需六条指令:
变址寻址与基址寻址的复合
在执行过程中,地址码7、2、17会先进行基址寻址,加上100得到107、102、117,之后再执行指令。
变址寻址与基址寻址的区别
基址寻址面向系统,主要用于多道程序或数据分配存储空间,因此基址寄存器的内容通常由操作系统或管理程序确定,在程序执行过程中其值不可变,而指令字中的A是可变的;变址寻址立足于用户,主要用于处理数组问题,编制寄存器的内容由用户设定,在程序执行过程中其值可变,而指令字中的A是不可变的。
相对寻址
以程序计数器PC的值作为起点。
对于转移类指令
J
M
P
A
JMP\quad A
JMPA,若其采用的是相对寻址,则当CPU从存储器中取出一字节时,会自动执行
(
P
C
)
+
1
−
>
P
C
(PC)+1->PC
(PC)+1−>PC,若转移指令地址为X,占2B,在取出该指令后,PC的值会加2,即
(
P
C
)
=
X
+
2
(PC)=X+2
(PC)=X+2,故在执行完该指令后,会自动跳转到
X
+
2
+
A
X+2+A
X+2+A的地址继续执行。
相对寻址作用举例
若将该段代码移动到内存地址为M,处:
此时执行的跳转指令就会跳出for循环而执行出错,事实上,当取出该跳转指令后,PC会自动加1,即
(
P
C
)
=
M
+
4
(PC)=M+4
(PC)=M+4,应将
P
C
PC
PC修改为M,故可采用相对寻址的方式进行跳转:
使for循环可正常执行。
注意:事实上,图中的数组地址形式7一直是未改变的,这是因为计算机系统常常使用分段的方式,将程序段、数据段分开,用数据段专门存放数据,故数组a的形式地址7无需改变。
堆栈寻址
上图中给出的是由四个寄存器组成的堆栈,SP内容为00,表示指向的是
R
0
R_0
R0(只有四个寄存器,2位即可)。若想用栈顶的两个元素完成加法操作,可使用指令
P
O
P
A
C
C
POP\quad ACC
POPACC表示将栈顶元素弹出,并存入累加寄存器ACC当中,实际执行过程为:
(
M
s
p
−
>
A
C
C
)
(
S
P
)
+
1
−
>
S
P
(M_{sp}->ACC)\\(SP)+1->SP
(Msp−>ACC)(SP)+1−>SP
表示将栈顶元素存入ACC当中,SP值加1,指向次栈顶(寄存器
R
1
R_1
R1),同理使用指令
P
O
P
X
POP\quad X
POPX表示将栈顶元素弹出,并存入累加寄存器X当中,如下图所示:
(相当于对两元素的逻辑删除)
执行指令
A
D
D
Y
ADD\quad Y
ADDY表示将两操作数相加并存入寄存器Y当中,之后再执行指令
P
U
S
H
Y
PUSH\quad Y
PUSHY表示将寄存器Y中的值压栈,最终得到:
(上述例子是假设栈顶在小地址的方向,实际考试中可能对两种情况都进行考察)
总结
上述过程中由寄存器实现的堆栈称为硬堆栈,寄存器成本较高,不适合作大容量堆栈,而从主存划分出一段区域来做堆栈是常用的方法,称为软堆栈,此时SP中存放的是主存地址。
采用堆栈结构的计算机系统中,大部分指令表面上都表现为无操作数指令格式,因为操作数地址都隐含使用了SP,通常情况下,在读/写堆栈的一个单元的前后都伴有自动完成对SP内容的增量或减量的操作。
4.3扩展:由硬件实现数的比较
4.4程序的机器级代码表示
4.4.1常用汇编指令
4.4.1.1常见算术运算指令
4.4.1.2常见逻辑运算指令
4.4.1.4选择语句
4.4.1.5选择语句
4.4.2AT&T格式与Intel格式
以定义一个
S
t
u
d
e
n
t
Student
Student结构体数组为例,假设每个学生结构体的大小为32B,要获取第4个学生的
a
g
e
age
age信息,可通过基址
e
b
x
ebx
ebx的值获取该结构体数组的起始地址,通过
e
c
x
∗
32
ecx*32
ecx∗32定位到第4个学生的起始地址,再加上偏移量4,即可得到其
a
g
e
age
age变量的起始地址。
4.4.3函数调用的机器级表示
4.4.3.1call指令和ret指令
程序运行时,系统会为其分配一片内存区域,将这片区域成为函数调用栈,如函数caller()的栈帧中保存了定义的变量temp1、temp2,而其调用add()函数时所传递的参数temp1、temp2也同样保存在caller()的栈帧当中。当caller()执行完后其栈帧也会相应出栈。
下面给出caller()函数与add()函数的汇编语言代码:
汇编语言中使用call和ret语句进行函数的调用与返回,且使用一个标号(函数名)标记函数起始地址,使用冒号表示接下来是函数的函数体,故可将call与函数名配合使用进行函数的调用,最后使用ret指令进行返回,返回到call调用语句的下一条语句继续执行。事实上,这两条指令是通过改变PC的值来改变程序的执行流(x86处理器中称为IP)。
以上图为例,当执行
c
a
l
l
a
d
d
call\quad add
calladd指令时,IP保存的是指令
m
o
v
[
e
b
p
−
4
]
,
e
a
x
mov\quad [ebp-4],eax
mov[ebp−4],eax的地址,故call指令会先将该地址(称为IP旧值)压栈,保存在函数调用栈的栈帧顶部(仍属于caller的栈帧)。之后会将IP的值改为add()函数的起始地址,即为该函数第一条语句
p
u
s
h
e
b
p
push\quad ebp
pushebp的起始地址(称为IP新值),即:
接下来依次执行add()函数函数中的所有内容,直到执行ret指令:
执行完ret指令后,IP的值为之前的IP旧值,使得函数的执行流可回到正确的位置。
总结
4.4.3.2如何访问栈帧
a.为什么栈底在上,而栈顶在下?
32位的操作系统会为进程分配4GB的虚拟地址空间,高1GB为内核空间,而低3GB为用户空间,由于用户栈的栈底为高地址,栈顶为低地址,故通常将栈底画在上方,栈顶画在下方:
注:由操作系统知识可知,⽤户空间的代码只能访问⼀个局部的内存空间,而内核空间的代码可以访问所有内存空间,且一个进程既有用户栈也有内核栈,不同进程的内核栈也是相互独立的。
b.标记栈帧的范围:EBP、ESP寄存器
e
b
p
ebp
ebp指向当前栈帧的栈底,而
e
s
p
esp
esp指向当前栈帧的栈顶,在x86系统中,默认以4B为栈的操作单位。
上图中的
e
b
p
ebp
ebp与
e
s
p
esp
esp标记了函数add()的范围,当函数add()执行完退回call()函数时,只需修改
e
b
p
ebp
ebp与
e
s
p
esp
esp的值即可完成修改,使之分别指向caller()函数的顶部4B与底部4B。
事实上,
e
b
p
ebp
ebp与
e
s
p
esp
esp中存储的即为主存地址,下面探究如何使用汇编语言结合这两个寄存器对栈中的数据进行读和写。
c.访问栈帧数据:push、pop指令
执行第一条指令后的效果(注意是以4B为操作单位):
执行第二条指令后的效果:
执行第三条指令后的效果:
执行第四条指令后的效果:
执行第五条指令后的效果:
c.访问栈帧数据mov指令
由于pop指令只能对栈顶的位置进行读或写,这样使得对栈中其他部分进行操作时十分不方便,而使用mov指令可方便实现这一功能:
开始时
e
b
p
ebp
ebp与
e
s
p
esp
esp分别指向add()函数栈帧的栈帧底部与栈帧顶部,执行第一条指令,修改
e
s
p
esp
esp的值:
执行第二条指令:
执行第三条指令:
执行第四条指令:
执行第五条指令:
执行第六条指令:
4.4.3.3如何切换栈帧
a.函数调用时栈帧的切换
函数调用时栈帧的切换通过以下两条指令完成(每个函数开头都会出现的例行处理):
上图中绿色部分是caller()函数的栈帧,当执行指令
c
a
l
l
a
d
d
call\quad add
calladd时,IP寄存器此时指向的是
m
o
v
[
e
b
p
−
4
]
,
e
a
x
mov\quad [ebp-4],eax
mov[ebp−4],eax指令的地址,执行完
c
a
l
l
call
call指令之后(指令地址压栈保存,同时IP指向add函数第一条指令的地址):
当开始执行
p
u
s
h
e
b
p
push\quad ebp
pushebp指令后,IP的值自动加1,该指令作用为将
e
b
p
ebp
ebp寄存器中的栈底地址压栈保存:
从而得到:
之后执行指令
m
o
v
e
b
p
,
e
s
p
mov\quad ebp,esp
movebp,esp,将寄存器
e
s
p
esp
esp(栈顶地址)赋值给寄存器
e
b
p
ebp
ebp作为新的栈基地址,使
e
b
p
ebp
ebp与
e
s
p
指向同一地址
esp指向同一地址
esp指向同一地址:
从这一过程可发现,每一个函数栈帧的底部都存储着上一层函数的基地址,使得当一个函数执行结束,要返回之前函数时,总能在当前函数的栈帧底部找到上一层函数的基地址,从而恢复
e
b
p
ebp
ebp寄存器的值。
补充:enter指令
上述两条切换栈帧的指令可用一条零地址指令
e
n
t
e
r
enter
enter代替
b.函数返回时栈帧的切换
函数返回时栈帧的切换通过以下两条指令完成:
当执行指令
m
o
v
e
s
p
,
e
b
p
mov\quad esp,ebp
movesp,ebp时,会将
e
b
p
ebp
ebp的值赋值给
e
s
p
esp
esp,即将二者共同指向栈帧的底部(此处保存上一栈帧的基址):
之后执行指令
p
o
p
e
b
p
pop\quad ebp
popebp,用于将
e
b
p
ebp
ebp所指向元素出栈并写入
e
b
p
ebp
ebp寄存器,即得到:
故而,当一个函数执行完时,只需执行这两条指令,即可让函数栈帧切换回上一层函数的栈帧。
事实上,这两条指令执行的效果等价于
l
e
a
v
e
leave
leave指令,用于恢复上一层函数的栈帧,这也是每个函数返回之前要做的例行处理:
事实上,在
c
a
l
l
e
r
(
)
caller()
caller()函数执行
c
a
l
l
a
d
d
call\quad add
calladd指令时已将
m
o
v
[
e
b
p
−
4
]
,
e
a
x
mov\quad [ebp-4],eax
mov[ebp−4],eax的地址(IP旧值)压入
c
a
l
l
e
r
(
)
caller()
caller()栈帧的栈顶,故
r
e
t
ret
ret指令实际就是改变IP的值,从而改变程序的执行流。
总结
4.4.3.4栈帧中包含哪些内容以及如何传递参数、返回值
以
c
a
l
l
e
r
(
)
caller()
caller()函数为例,其栈帧底部保存了上一层函数(P()函数)的栈帧基址,而当
c
a
l
l
e
r
(
)
caller()
caller()函数调用
a
d
d
(
)
add()
add()函数时用到
a
d
d
add
add指令,从而将IP的值(
c
a
l
l
call
call指令下一条指令的地址)压到
c
a
l
l
e
r
(
)
caller()
caller()函数的栈帧顶部保存。
所有在函数内部定义的局部变量,都会集中存储在栈帧底部区域位置,且注意到越靠前定义的局部变量越靠近栈顶(地址越小),只需基于函数的
e
b
p
ebp
ebp指针即可访问到这些局部变量(一般遇到
[
e
b
p
−
4
]
、
[
e
b
p
−
8
]
[ebp-4]、[ebp-8]
[ebp−4]、[ebp−8]指令,都是在访问函数内部定义的局部变量,且
[
e
b
p
−
4
]
[ebp-4]
[ebp−4]对应最后定义的变量,而
[
e
b
p
−
8
]
[ebp-8]
[ebp−8]对应倒数第二次定义的变量)。
栈顶区域存放函数调用时传递的参数,其中,参数列表靠前的参数靠近栈帧顶部,使得当执行
a
d
d
(
)
add()
add()函数时,只需结合
e
b
p
ebp
ebp的值就能访问到这些传递参数,如使用
[
e
b
p
+
8
]
[ebp+8]
[ebp+8]即可访问到参数
x
x
x,使用
[
e
b
p
+
12
]
[ebp+12]
[ebp+12]即可访问到参数
y
y
y(
[
e
b
p
+
4
]
[ebp+4]
[ebp+4]的值为IP旧值)。
gcc编译器为追求数据对齐会将每个栈帧的大小设置为16B整数倍(指的的切换栈帧时进行设置),上图中
c
a
l
l
e
r
(
)
caller()
caller()函数的栈帧大小即为32B。
4.4.3.5汇编代码实战
由
P
(
)
P()
P()函数调用了
c
a
l
l
e
r
(
)
caller()
caller()函数,在执行
c
a
l
l
e
r
(
)
caller()
caller()函数的
p
u
s
h
e
b
p
m
o
v
e
b
p
,
e
s
p
push\quad ebp\\mov\quad ebp,esp
pushebpmovebp,esp代码时,会将
P
(
)
P()
P()函数的栈帧基地址压栈保存,再让
e
b
p
ebp
ebp寄存器指向
c
a
l
l
e
r
(
)
caller()
caller()函数的栈帧底部:
之后再执行指令
s
u
b
e
s
p
,
24
sub\quad esp,24
subesp,24,相当于给
c
a
l
l
e
r
(
)
caller()
caller()的栈帧划分了空间:
执行指令
m
o
v
[
e
b
p
−
12
]
,
125
m
o
v
[
e
b
p
−
8
]
,
80
mov\quad [ebp-12],125\\mov\quad [ebp-8],80
mov[ebp−12],125mov[ebp−8],80即完成了temp1、temp2变量的初始化,而sum变量的值实际在完成
a
d
d
(
)
add()
add()函数的调用后被赋值的,其最终的位置应在
[
e
b
p
−
4
]
[ebp-4]
[ebp−4]处:
在
c
a
l
l
call
call指令发起之前,需要向栈帧顶部的区域写入将要传入的两个参数temp1与temp2,首先执行:
m
o
v
e
a
x
,
[
e
b
p
−
8
]
m
o
v
[
e
s
p
+
4
]
,
e
a
x
mov\quad eax,[ebp-8] mov [esp+4],eax
moveax,[ebp−8]mov[esp+4],eax
先将temp2的值赋值给
e
a
x
eax
eax寄存器,再将
e
a
x
eax
eax寄存器的值赋值给
[
e
s
p
+
4
]
[esp+4]
[esp+4],即传递参数temp2(之所以不使用
m
o
v
[
e
s
p
+
4
]
,
[
e
b
8
]
mov\quad [esp+4],[eb8]
mov[esp+4],[eb8]是因为mov指令不支持两个操作数同时来自主存),之后再执行:
m
o
v
e
a
x
,
[
e
b
p
−
12
]
m
o
v
[
e
s
p
]
,
e
a
x
mov\quad eax,[ebp-12] mov [esp],eax
moveax,[ebp−12]mov[esp],eax
从而完成了参数的传递。
通过执行
c
a
l
l
a
d
d
call\quad add
calladd将IP旧值压入栈顶,并将程序的执行流转移到
a
d
d
(
)
add()
add()函数的第一条指令,其中
p
u
s
h
push
push与
m
o
v
mov
mov指令分别完成保存
c
a
l
l
e
r
(
)
caller()
caller()函数栈帧基址与切换栈帧的工作:
之后依次执行:
m
o
v
e
a
x
,
[
e
b
p
+
12
]
m
o
v
e
d
x
,
[
e
b
p
+
8
]
a
d
d
e
a
x
,
e
d
x
mov\quad eax,[ebp+12]\\mov\quad edx,[ebp+8]\\add\quad eax,edx
moveax,[ebp+12]movedx,[ebp+8]addeax,edx
表示先将80赋值给
e
a
x
eax
eax寄存器,将125赋值给
e
d
x
edx
edx寄存器,之后再使用
a
d
d
add
add指令执行加法运算,将运算结果保存到
e
a
x
eax
eax寄存器当中:
之后再执行
l
e
a
v
e
leave
leave与
r
e
t
ret
ret指令分别完成切换栈帧与回到上一层函数执行流的工作,且此时运算结果保存在了
e
a
x
eax
eax寄存器当中:
执行指令
m
o
v
[
e
b
p
−
4
]
,
e
a
x
mov\quad [ebp-4],eax
mov[ebp−4],eax,将运算结果存入
[
e
b
p
−
4
]
[ebp-4]
[ebp−4]处作为sum变量的值,再执行
m
o
v
e
a
x
,
[
e
b
p
−
4
]
mov\quad eax,[ebp-4]
moveax,[ebp−4],将sum变量的值赋值给
e
a
x
eax
eax寄存器作为
c
a
l
l
e
r
(
)
caller()
caller()函数的返回值。
故而,通过函数调用栈来传递函数调用时的多个参数,而由于函数的返回值只有一个,故只需1个
e
a
x
eax
eax寄存器保存返回结果即可。
4.4.3.6对于函数调用栈栈帧内容的补充
假设在发生函数调用时,调用者的一些运算结果保存在
e
a
x
、
e
d
x
、
e
c
x
eax、edx、ecx
eax、edx、ecx寄存器中,由于函数调用发生时,被调用函数也可能使用到这些寄存器,从而将原先内容覆盖而丢失数据,为此,可在发起函数调用之前将这些数据压栈保存,而在函数调用返回值将这些值恢复。
解决上述问题有两种策略:
- 调用者保护:在函数A在调用函数B之前提前保存寄存器的内容,执行完函数B之后再恢复 寄存器的内容,这一过程称为调用者保护,常见的调用者保护寄存器如 e a x 、 e c x 、 e d x eax、ecx、edx eax、ecx、edx。
- 被调用者保护:函数B在使用寄存器%rbx,先保存寄存器的值,在函数B返回之前,要恢复寄存器原来存储的内容,这种策略被称之为被调用者保存,常见的被调用者保护寄存器如 e b x 、 e s i 、 e d i ebx、esi、edi ebx、esi、edi。
4.4.3.7小结
4.5CISC与RISC
4.6本章小结
五、中央处理器
5.1CPU的功能和基本结构
5.1.1概述
CPU由运算器和控制器组成,其中控制器负责协调并控制计算机各部件执行程序的指令序列,包括取指令、分析指令和执行指令,运算器的功能是对数据进行加工。
CPU的基本功能:
运算器的基本功能:接收从控制器发送来的命令并执行相应操作,对数据进行加工和处理。
控制器的基本功能:
控制器有硬布线控制器和微程序控制器两种类型。
5.1.2运算器的基本结构
专用数据通路:导线、多路选择器、三态门。
每个寄存器与ALU之间都有专门的数据通路,这种数据通路称为专用数据通路,即在两个部件之间安排专用的线路传输数据。在加入MUX与三态门后,可由控制信号决定是否输出。
对于三态门而言,其一般有三个接口,包括数据的输入与输出及控制信号的输入,当控制信号有效时,三态门才能传输数据。(
R
0
o
u
t
R0_{out}
R0out信号表示R0能否输出数据)
在CPU内部单总线的方式下,所有寄存器的输入端和输出端都连接到一条公共的通路上,既可将信号输入到总线,也可从总线接收信号。在上图中当
R
0
o
u
t
R0_{out}
R0out信号为有效时,R0的数据会被输出到总线上,若想要将
R
0
R0
R0的数据传送到
R
2
R2
R2中时,只需给
R
2
R2
R2的
R
2
i
n
R2_{in}
R2in有效电平,给
R
0
R0
R0的
R
0
o
u
t
R0_{out}
R0out有效电平既可。
在上图连接方式下,执行
A
D
D
R
0
,
R
1
ADD\quad R0,R1
ADDR0,R1时,若二者的数据同时输出到总线上,就会发生冲突。此时可在其中一端设置暂存寄存器,可先将
R
0
R_0
R0的数据输出到暂存寄存器中保存,撤销
R
0
R0
R0的
R
0
o
u
t
R0_{out}
R0out有效电平并使
R
2
R2
R2的
R
2
i
n
R2_{in}
R2in电平有效,从而避免发生冲突。
且为避免ALU输出的信号和通用寄存器的输出信号冲突,可在ALU输出端再加入暂存寄存器,等ALU输出结果稳定之后再输出到内部总线。
5.1.3控制器的基本结构
控制器的工作原理是,根据指令操作码、指令的执行步骤(微命令序列)和条件信号来形成当前计算机各部件要用到的控制信号。
- PC自动加1的功能是通过送给ALU来实现的。
- 一条指令往往有多个地址码,其指明操作数的存放地址,故其需要输出到内部总线上,而操作码会先被送给指令译码器,根据译码器的输出信号就可知需执行哪些微操作。故而译码器的输出信号会作为微操作信号发生器的输入信号,用于判断指令所对应的微操作序列。
- 时序系统可发出时序信号,微操作发生器收到一个时序信号就可发出下一个微操作对应的操作信号。
- PSW也会对微操作信号发生器发出信号,共同决定下一微操作信号。
如
P
C
i
n
PC_{in}
PCin、
P
C
o
u
t
PC_{out}
PCout这样的信号是否有效实际就是由微操作信号发生器发出的微操作信号决定的。
M
A
R
MAR
MAR、
M
D
R
MDR
MDR的信号可输出到外部的地址总线、数据总线上,使得主存可获取信息。
M
D
R
i
n
MDR_{in}
MDRin表示来自CPU内部的输入有效信号,
M
D
R
i
n
E
MDR_{in}E
MDRinE表示来自CPU外部总线的输入有效信号。
CPU内部总线是指CPU内部部件之间数据传送的通路,而CPU外部总线是指CPU与其它部件,如主存、I/O设备,之间的数据通路。
5.1.3CPU的基本结构
用户可见寄存器实际是指用户可通过汇编语言来改变寄存器内部的值(。
- 用户可见寄存器:PC、PSW、ACC、通用寄存器组。
- 用户不可见寄存器:IR、MAR、MDR、暂存寄存器、移位寄存器。
5.1.4总结
5.2指令执行过程
5.2.1指令周期
指令周期是指CPU从主存中取出并执行一条指令所需的全部时间,指令周期至少包含取指周期,而一个完整的指令周期包括取指周期、间址周期、执行周期和中断周期。
- 取指周期:根据PC中的内容从主存取出指令并放入IR中,同时PC加1.
- 间址周期:取得操作数的有效地址。
- 执行周期:根据IR中的指令字操作码和操作数通过ALU运算得出结果,不同指令执行周期不同,故无统一数据流向。
- 中断周期:当CPU采用中断方式实现主机与I/O设备的信息交换时,CPU在每条指令执行结束前都会发出中断查询信号,若有中断请求,则CPU进入中断响应阶段,又称中断周期。
以上四个工作周期都包含有CPU访存操作,但访存目的不同,取指周期是为取指令,间址周期是为取有效地址,执行周期是为取操作数,中断周期是为保存程序断点。
上图中指令周期被划分为取指周期与执行周期,取指令是需要访存的,其执行时间远大于指令译码的时间(取出指令时就已完成指令译码),故将译码操作归为取指周期内。
时钟周期(T周期、CPU周期)是CPU操作的基本单位,用时钟信号(由电路产生,频率即为CPU主频)控制节拍发生器产生节拍,每个节拍的宽度等于一个时钟周期,每个节拍内可完成一个或多个需同时完成的操作。事实上,每个指令周期内机器周期数可不等,每个机器周期内的节拍数也可不等(所需执行的微操作不同)。
对于无条件转移指令
J
U
M
P
X
JUMP\quad X
JUMPX,其在执行时无须访问主存,只包含取值阶段和执行阶段;对于间接寻址的指令,为取操作数需先访问主存取出有效地址,再访问主存取出操作数,故还需包括间址周期。
CPU中设置4个标志触发器FE、IND、EX和INT用于标识当前处于哪一周期中,以"1"表状态有效。
5.2.2指令周期的数据流
数据流:根据指令要求依次访问的数据序列。
5.2.2.1取值周期
PC中存放将执行指令的地址,改地址送到MAR后通过地址总线送入主存进行地址译码,并由控制部件CU发出读命令,使该地址所指内容(指令)通过数据总线送入MDR再送入指令译码器IR进行指令译码,并由CU发出控制信号使PC自动加1.
事实上此处省略了
O
P
(
I
R
)
−
>
指令译码器
OP(IR)->指令译码器
OP(IR)−>指令译码器,即将操作码送入ID,微操作信号发生器通过ID的输出信号以发出控制信号。
5.2.2.2间址周期
一旦取指周期结束,CPU会根据
I
R
IR
IR中的寻址特征位判断是否有间址操作,若有,则MDR中指示的地址码(记作
A
d
(
M
D
R
)
Ad(MDR)
Ad(MDR))或指令寄存器中的地址码(记作
A
d
(
I
R
)
Ad(IR)
Ad(IR))会被送入MAR并送入地址总线,再送入主存的地址译码器,同时CU通过控制总线发出读命令以取出有效地址并存至MDR。
此处隐含了将有效地址与指令进行拼接的操作,即
(
M
D
R
)
−
>
A
d
(
I
R
)
(MDR)->Ad(IR)
(MDR)−>Ad(IR)。
5.2.2.3执行周期
执行周期的任务是取操作数,并根据IR中指令字的操作码通过ALU操作产生执行结果,不同指令的执行周期不同,无统一数据流向。
5.2.2.4中断周期
SP当中存放的是主存地址,故需将PC的内容(此时已加1,即为原本下一条将要指令的地址)作为断点写入主存,故需先将SP减1,并在SP所指的主存单元中写入该断点,之后再转到中断处理程序的入口地址(第一条指令的地址)。
注意,此处隐含了
M
D
R
−
>
B
U
S
−
>
M
(
M
A
R
)
MDR->BUS->M(MAR)
MDR−>BUS−>M(MAR),即将断点写入主存(堆栈)。
5.2.3指令执行方案
一个指令周期通常要包括几个时间段(执行步骤),每个步骤完成指令的一部分功能,几个依次执行的步骤完成这条指令的全部功能,出于性能和硬件成本等考虑,可选用三种不同的方案安排指令的执行步骤。
流水线方案的思想在于,不同指令不同阶段所执行的操作不同,所需的硬件资源亦不同,可并发执行相容不冲突使用资源的指令不同阶段,以提高利用率。
5.2.4总结
指令周期、机器周期与时钟周期
- 指令周期:CPU每取出并执行一条指令所需的全部时间。
- 机器周期:执行指令周期中一步相对完整的操作所需的时间,机器周期可视为所有指令执行过程中的一个基准时间,而访问一次存储器的时间是固定的,故常采用存取周期作为基准时间(机器周期),此时,当存储字长等于指令字长时,取指周期可视为一个机器周期。
- 时钟周期:计算机主时钟的周期时间,是计算机运行时最基本的时间单位,对应完成一个微操作所需的时间。
5.3数据通路的功能和基本结构
5.3.1数据通路概述
数据通路是指数据在功能部件之间传送的路径,数据通路由控制部件控制,控制部件会根据每条指令功能的不同生成对数据通路的控制信号,数据通路的功能是实现CPU内部的运算器与寄存器与寄存器及寄存器之间的数据交换。
即,内部单总线方式同一时刻只允许一组部件交换数据,内部多总线方式同一时刻允许多组部件交换数据,而专用数据通路是使用专门的线路交换数据。
5.3.2CPU内部单总线方式
CPU内部单总线方式下,所有寄存器的输入端与输出端都连接到一条公共通路上,结构简单,但数据传输存在较多冲突现象,性能较低。连接各部件的总线只有一条时,称为单总线结构,CPU中有两条或多条总线时,构成双总线结构或多总线结构。
注意,由于是内部单总线方式,同一时刻总线上只能有一个部件的输入信号有效,而
A
L
U
ALU
ALU需要两个输入,故可先将一个加数存入暂存寄存器
Y
Y
Y中,而
Y
Y
Y与
A
L
U
ALU
ALU之间有专用数据通路,无需占用总线,就可通过总线将
A
C
C
ACC
ACC中的另一操作数与其同时输入
A
C
C
ACC
ACC中。
其中
(
R
0
)
(R0)
(R0)表示寄存器
R
0
R0
R0中存放的是目的操作数的有效地址,故需一次寻址,而
R
1
R1
R1中存放的是源操作数。
5.3.3专用数据通路方式
专用数据通路:根据指令执行过程中的数据和地址的流动方向安排连接线路,避免使用共享的总线,性能较高,但硬件量大。
(3):
(4):
(5):
(6):
5.4控制器的结构和功能
5.4.1概述
控制器的主要功能有:
- 从主存中取出一条指令,并指出下一条指令在主存中的位置。
- 对指令进行译码或测试,产生相应的操作控制信号,以便启动规定的动作。
- 指挥并控制CPU、主存、输入和输出设备之间的数据流动方向。
根据控制器产生微操作控制信号的不同,控制器可分为硬布线控制器和微程序控制器,两类控制器中的PC和IR相同,但确定和表示指令执行步骤的办法以及给出控制各部件运行所需的控制信号的方案不同。
微操作与微命令:
- 微命令:由控制部件向执行部件发出的控制信号(如前文介绍的使 P C o u t PC_{out} PCout有效的电平信号),它是构成控制序列的最小单位。
- 微操作:微操作是微命令的执行过程,一条机器指令可分解为一个微操作序列,这些微操作是计算机中最基本的、不可再分解的操作。
微命令与微操作一一对应(控制部件发出控制信号就会使执行部件执行相应操作),微命令是微操作的控制信号,而微操作是微命令的执行过程。微操作之间有相容性与互斥性,相容的微命令可同时产生、共同完成某一些微操作的微命令,而互斥性微命令是指在机器中不允许同时出现的微命令。
不同指令在取指、间址、中断周期应执行的微操作基本一致。
5.4.2硬布线控制方式
硬布线控制方式根据指令的要求、当前的时序及外部和内部状态,按时间的顺序发送一系列微操作控制信号,它由复杂的组合逻辑门电路和一些触发器构成,因此又称组合逻辑控制器。
信号来源:
- 现行指令操作码经指令译码器译码传送的指令信息决定所需完成的操作。
- 时序系统产生的机器周期信号和节拍信号,一个时钟脉冲使控制单元发送一个操作命令,或发送一组需要同时执行的操作命令。(图中的 T 0 、 T 1 、 . . . 、 T m T_0、T_1、...、T_m T0、T1、...、Tm表示一个机器周期有 ( m + 1 ) (m+1) (m+1)个时钟周期,之后会改变四个触发器的状态)
- 来自执行单元的反馈信息。
CPU的控制方式
控制单元控制一条指令执行的过程,实质上是依次执行一个确定的微操作序列的过程,由于不同指令所对应的微操作数及复杂程度不同,因此每条指令和每个微操作所需的执行时间也不同。主要有以下3中控制方式:
5.4.3微程序控制器
微程序设计思想将每条机器指令编写成一个微程序,每个微程序包含若干微指令,每条微指令对应一个或几个微操作命令。这些微程序可存放到一个控制存储器中,用寻址用户程序机器指令的办法来寻址每个微程序中的微指令。
一般一条机器指令对应一个微程序,由于任何一条机器指令的取指操作均相同,故可将取指令操作的微命令统一编成一个微程序,这个微程序只负责将指令从主存取出并送至指令寄存器。同样,亦可编写对应间址周期和中断周期的微程序,此时控制存储器中的微程序个数应为机器指令数加上取值、间址和中断周期等共用的微程序个数。
5.4.4微指令的设计
5.4.4.1微指令的格式
微指令的格式分为水平型微指令和垂直型微指令两种。
从编码方式上来看,直接编码、字段直接编码、字段间接编码和混合编码都属于水平型微指令。
5.4.4.2微指令后继地址的形成方式
后继地址的形成主要有以下几种:
测试网络相当于处理电路,类比于微地址形成部件。
电源加电后,第一条微指令的地址可由专门的硬件电路产生,也可由外部直接向CMAR输入微指令的地址,这个地址即为取值周期微程序的入口地址。
5.4.4.3总结
5.4.5微程序控制单元的设计
5.4.6动态微程序设计和毫微程序设计
5.4.7硬布线和微程序控制器的比较
5.5指令流水线
5.5.1基本概念与性能指标
现代计算机普遍采用指令流水线技术,同一时刻有多条指令在CPU不同功能部件执行,从而大大提高功能部件的并行性和程序执行效率。
可从两个方面提高处理器的并行性:
- 时间上的并行技术:将一个任务分解为几个不同的子阶段,每个阶段在不同的功能部件上并行执行,以便在同一时刻能同时执行多个子任务,进而提升系统性能,称为流水线技术。
- 空间上的并行技术:在一个处理机内设置多个执行相同任务的功能部件,并让这些功能部件并行工作,这样的处理机称为超标量处理机。
指令流水线有吞吐量、加速比与效率三大性能指标。
5.5.2五段式指令流水线
五段式指令流水线是由
M
I
P
S
MIPS
MIPS架构提出的模型,
M
I
P
S
MIPS
MIPS架构是世界上第一个
R
I
S
C
RISC
RISC指令集的指令系统,它将指令的执行划分为五个阶段,即便有的指令在实际运行时无需中间某个机器周期的处理,也需耗费该机器周期的时间。
- 取指(IF):根据PC的值,从指令存储器或Cache中取指令并放入锁存器当中。
- 译码/读寄存器(ID):操作控制器对指令进行译码,同时从寄存器堆(通用寄存器组)中取操作数放入锁存器 A A A、 B B B、 I m m I_{mm} Imm(在 R I S C RISC RISC指令集中,参与运算的操作数必须都从寄存器中取出,对于存放在主存中的数据,也必须先通过 L O A D LOAD LOAD指令取出放入寄存器组再从寄存器组取出)( I m m I_{mm} Imm是立即数寄存器,当指令是立即寻址时,可直接从指令中取出该操作数并放入 I m m I_{mm} Imm寄存器)。
- 执行/计算地址(EX):使用 A L U ALU ALU执行运算操作或计算地址。
- 访存(M):对存储器进行读写操作(实际是写入数据Cache)。
- 写回(WB):将指令执行结果写回寄存器堆。
如
I
D
ID
ID阶段获得结果的时刻为
180
n
s
180ns
180ns,而
E
X
EX
EX阶段获取数据的时刻为
200
n
s
200ns
200ns,为此而在每个流水段后面设有一个缓冲寄存器(锁存器),其作用是保存本流水段的执行结果,提供给下一流水段使用。各种寄存器和数据存储器均采用统一时钟
C
L
K
CLK
CLK进行同步,每来一个时钟,就会有一条新的指令进入流水段
I
F
IF
IF,同时流水寄存器会锁存前段加工处理完成的数据和控制信号,为下一段的功能部件提供数据输入。
- L O A D LOAD LOAD指令:将主存中的数据取出并装入寄存器。
- S T O R E STORE STORE指令:将寄存器中的数据装入内存。
考试当中常见的有五类指令:运算类指令、LOAD指令、STORE指令、条件转移指令、无条件转移指令。
运算类指令
- I D ID ID段有 A 、 B 、 I m m A、B、I_{mm} A、B、Imm三个锁存器,其中 I m m I_{mm} Imm用于存放立即数。第一条指令将操作数从通用寄存器组 R e g i s t e r s Registers Registers取出,并放入 A 、 B A、B A、B锁存器当中,而第二条指令将操作数放入 B B B锁存器,将立即数放入 I m m I_{mm} Imm锁存器,第三条指令将操作数放入锁存器 A A A当中。
- 对于 R I S C RISC RISC精简指令集,参与运算的两个操作数一定是来自寄存器或是立即数,且运算结果也存入某个寄存器,故在 M M M阶段不会产生操作,但仍需消耗这一时间。
- W B WB WB阶段将运算结果写回通用寄存器组 R e g i s t e r s Registers Registers。
LOAD指令
L
O
A
D
LOAD
LOAD指令是
R
I
S
C
RISC
RISC指令集中用于从主存中取出数据并存入寄存器的指令。
- L O A D R d , 996 ( R s ) LOAD\quad Rd,996(Rs) LOADRd,996(Rs):将 R s Rs Rs内容加上 996 996 996作为有效地址,取出该地址单元中的数据存入 R d Rd Rd寄存器当中。
- L O A D R d , m e m LOAD\quad Rd,mem LOADRd,mem:将地址 m e m mem mem所对应主存单元的数据取出并存入 R d Rd Rd寄存器当中。
STORE指令
条件转移指令
无条件转移指令
5.5.3指令流水线影响因素
在流水线流动的过程中,由于三种相关的存在,常常会出现断流的现象
- 结构相关/资源冲突:多条指令进入流水线后,硬件资源满足不了指令重叠执行的要求时产生。
- 数据相关/数据冲突:指令在流水线中重叠执行时,当后继指令需用到前面指令的执行结果时产生。
- 控制相关/控制冲突:流水线遇到分支指令和其他改变PC值的指令时产生。
不同类型指令在各流水段的操作
流水段 | A L U ALU ALU类指令 | L O A D / S T O R E LOAD/STORE LOAD/STORE指令 | 转移指令 |
---|---|---|---|
IF | 取指 | 取指 | 取指 |
ID | 译码+读寄存器堆 | 译码+读寄存器堆 | 译码+读寄存器堆 |
EX | 执行 | 计算访存有效地址 | 计算转移目标地址+设置条件码 |
MEM | —— | 访存(读/写) | 若条件成立,将转移目标地址送PC |
WB | 结果写回寄存器堆 | 将读出数据写入寄存器堆 | —— |
1.结构相关
- 访存冲突:大多数机器都将指令和数据保存在同一存储器,且访问口只有一个,若在某个时钟周期内既要执行
L
O
A
D
/
S
T
O
R
E
LOAD/STORE
LOAD/STORE等对操作数存储器有访问操作的指令,又要完成另一指令对的取指,则会发生访存冲突。
- 解决方案1:执行该类指令时暂停(一个或多个机器周期)取后一个指令的操作。
- 解决方案2:单独设置数据存储器和指令存储器,使取数和取指令操作各自在不同的存储器中进行。事实上,现代计算机通常引入Cache机制,L1Cache采用数据Cache和指令Cache分离的方式以避免资源冲突。
如上图,第4个时钟周期中,第
i
i
i条指令
L
O
A
D
LOAD
LOAD的
M
E
M
MEM
MEM段和第
i
+
3
i+3
i+3条指令的
I
F
IF
IF段发生访存冲突,可让流水线在完成前一条指令对数据存储器的访问时,暂停(此处为一个时钟周期)取后一条指令的操作:
2.数据相关
指在一个程序中,存在下一条指令会用到当前指令的执行结果的情况。数据相关可分为以下三类:
- 写后读相关(Read After Write,RAW):表示当前指令将数据写入寄存器后,下一条指令才能从该寄存器读取数据,否则先读后写,读到的就是错误数据。
- 读后写相关(Write After Read,WAR):表示当前指令读出数据后,下一条指令才能写该寄存器,否则先写后读,读到的就是错误数据。
- 写后写相关(Write After Write,WAW):表示当前指令写入寄存器后,下一条指令才能写该寄存器,否则下一条指令在当前指令之前写,将使寄存器的值不是最新值。
以上三种数据相关在按序流动的流水线中,只可能出现
R
A
W
RAW
RAW,而在非按序流动的流水线中,由于允许后进入流水线的指令超过先进入流水线的指令而先流出流水线,则除
R
A
W
RAW
RAW外,还可能发生
W
A
R
WAR
WAR、
W
A
W
WAW
WAW相关。例如:
RAW:
l
1
:
A
D
D
R
5
,
R
2
,
R
4
;
(
R
2
)
+
(
R
4
)
−
>
R
5
l
2
:
A
D
D
R
4
,
R
5
,
R
3
;
(
R
5
)
+
(
R
3
)
−
>
R
4
l1:ADD\quad R5,R2,R4;(R2)+(R4)->R5\\ l2:ADD\quad R4,R5,R3;(R5)+(R3)->R4
l1:ADDR5,R2,R4;(R2)+(R4)−>R5l2:ADDR4,R5,R3;(R5)+(R3)−>R4
WAR:
l
1
:
S
T
A
M
,
R
2
;
(
R
2
)
−
>
M
l
2
:
A
D
D
R
2
,
R
4
,
R
5
;
(
R
4
)
+
(
R
5
)
−
>
R
2
l1:STA\quad M,R2;(R2)->M\\ l2:ADD\quad R2,R4,R5;(R4)+(R5)->R2
l1:STAM,R2;(R2)−>Ml2:ADDR2,R4,R5;(R4)+(R5)−>R2
乱序发射,编写程序时希望
l
1
l1
l1在
l
2
l2
l2前完成,但优化手段导致
l
2
l2
l2在
l
1
l1
l1前发射。
WRW:
l
1
:
M
U
L
R
3
,
R
2
,
R
1
;
(
R
2
)
+
(
R
1
)
−
>
R
3
l
2
:
S
U
B
R
3
,
R
4
,
R
5
;
(
R
4
)
−
(
R
5
)
−
>
R
3
l1:MUL\quad R3,R2,R1;(R2)+(R1)->R3\\ l2:SUB\quad R3,R4,R5;(R4)-(R5)->R3
l1:MULR3,R2,R1;(R2)+(R1)−>R3l2:SUBR3,R4,R5;(R4)−(R5)−>R3
存在多个功能部件时,后一条指令可能比前一条指令先完成。
3.控制相关
在上图中,条件转移指令
B
e
q
Beq
Beq地址为12,而下一条顺序执行的指令地址为16(即每条指令为4B)。转移类指令会在
M
E
M
MEM
MEM阶段将转移目标地址送PC(条件成立的情况下),此时已取出并正在执行的、位于
16
、
20
、
24
16、20、24
16、20、24处的指令实际上是不应该执行的。
常见的转移类指令、函数调用与返回、中断处理、跳转指令等都会造成流水线断流。
常用的解决方法:
I 1 I_1 I1与 I 2 I_2 I2指令需要在 W B WB WB阶段之后才能将数据写入寄存器当中,而 I 3 I_3 I3的ID阶段需要取操作数和指令译码,故发生数据冲突。
5.5.4流水线的分类
5.5.5高级流水线技术
有两种增加指令级并行的策略:
- 多发射技术:采用多个内部功能部件,使流水线功能段能同时处理多条指令,处理机一次可发射多条指令进入流水线执行。
- 超流水线技术:增加流水线级数使更多的指令同时在流水线中重叠执行。
注:理想情况下一个机器周期等于一个时钟周期,以下叙述均为时钟周期。
1.超标量流水线技术/动态多发射技术
每个时钟周期可并发多条独立指令,以并行操作方式将两条或多条指令编译执行,为此需配置多个功能部件。超标量技术不能调整指令的执行顺序,因此通过编译优化技术,把可并行执行的指令搭配起来,挖掘更多指令并行性。
2.超流水技术
超流水线技术是在同一时钟周期的不同时间段发射指令,而超标量技术的指令同时发出。
超流水线技术是通过细化流水,提高主频,使得机器在一个周期内完成一个甚至多个操作(缩短原来流水线的处理器周期),其实质是用时间换取空间。流水线功能段划分越多,时钟周期就越短,指令吞吐率就越高,因此其是通过提高流水线主频的方式来提升流水线性能的。但是流水线级数越多,用于流水线寄存器的开销就越大,因此流水线级数有限制,并非越大越好。
超流水线CPU在流水线充满后,每个时钟周期还是执行一条指令,
C
P
I
=
1
CPI=1
CPI=1,但其主频更高,多发射流水线
C
P
U
CPU
CPU每个时钟周期可处理多条指令,
C
P
I
<
1
CPI<1
CPI<1,相对而言,多发射流水线成本更高,控制更复杂。
3.超长指令字技术/静态多发射技术
5.6多处理器的基本概念
5.6.1SISD、SIMD、MIMD的概念
5.6.2硬件多线程的基本概念
5.6.3多核处理器的基本概念
5.6.4共享内存多处理器的基本概念
5.7本章小结
六、总线
6.1总线概述
6.1.1基本概念
总线设备:总线上所连接的设备,按其对总线是否有控制功能可分为主设备和从设备两种。
- 主设备:获得总线控制权的设备。
- 从设备:被主设备访问的设备,只能响应主设备发来的各种总线命令。
总线特性
6.1.2总线分类
4.I/O总线:I/O总线主要用于连接中低速的I/O设备,通过I/O接口与系统总线相连接,目的是将低速设备与高速总线分离了,以提升总线的系统性能,常见的有USB、PCI总线。
6.1.3总线结构
- 主存总线:用于CPU和主存之间传送地址、数据和控制信息。
- I/O总线:用于CPU和各类外设之间通信。
- DMA总线:用于在主存和高速外设之间直接传送数据。
6.1.4总线的性能指标
6.2总线事务和定时
总线定时是指总线在双方交换数据的过程中需要时间上配合关系的控制,这种控制称为总线定时,其实质是一种协议或规则,主要有同步和异步两种基本定时方式。
6.2.1总线事务
总线事务是指从请求总线到完成总线使用的操作序列,它是在一个总线周期中发生的一系列活动。
总线事务的传输阶段,主、从设备之间一般只能传输一个字长的数据。
突发(猝发)传送方式能进行连续成组数据的传输,其寻址阶段发送的是连续数据单元的首地址,在传输阶段传送多个连续单元的数据,每个时钟周期可传送一个字长的信息,但是不释放总线,直到一组数据全部传送完毕后,再释放总线。
6.2.2总线定时
6.3本章小结
七、输入/输出系统
7.1概述
7.2I/O接口
7.2.1I/O接口的功能
7.2.2I/O接口的工作原理
I/O接口在主机侧通过I/O总线与内存、CPU相连,通过数据总线,在数据缓冲寄存器与内存或CPU的寄存器之间进行数据传送。同时接口和设备的状态信息被记录在状态寄存器中,通过数据线将状态信息送到CPU。CPU对外设的控制命令也通过数据线传送,一般将其送到I/O接口的控制寄存器。状态寄存器和控制寄存器在传送方向上相反。
CPU向控制寄存器发射命令,I/O控制逻辑取出命令后寄存器空闲,设备可将状态信息保存到该寄存器,用于反馈给CPU查询。由于状态寄存器、控制寄存器在使用时间上是错开的,因此有的I/O接口可将二者合二为一。
CPU操作不同设备的实质是操作不同的寄存器组。
7.2.3I/O端口及其编址
7.2.4I/O的类型
7.2.5总结
7.3I/O方式
当输入/输出系统实现主存与I/O设备之间的数据传输时,采用不同的控制方式称为I/O方式,常见的I/O方式有程序查询方式、程序中断方式、DMA方式。
- 程序查询方式:CPU不断轮询检查I/O控制器中的“状态寄存器”,检测到状态为“已完成”之后,再从数据寄存器取出输入数据。
- 程序中断方式:等待键盘I/O时CPU可以先去执行其他程序,键盘I/O完成后I/O控制器向CPU发出中断请求,CPU响应中断请求,并取走输入数据。
对于快速I/O设备,如磁盘,每准备好一个字就给CPU发送一次中断请求(因为CPU一次读取一个字),会导致CPU需要花大量的时间来处理中断服务程序,CPU利用率严重下降(而主存与磁盘数据交换时以块为单位)。
- DMA控制方式:主存与高速I/O设备之间有一条直接数据通路(DMA总线)。CPU向DMA接口发出“读/写”命令,并指明主存地址、磁盘地址、读写数据量等参数。DMA控制器自动控制磁盘与主存的数据读写,每完成一整块数据读写(如1KB为一整块) ,才向CPU发出一次中断请求。
- 通道控制方式:通道是具有特殊功能的处理器,能对I/O设备进行统一管理。
7.3.1程序查询方式
程序查询方式中,信息交换的控制完全由CPU执行程序实现,接口中需设置一个数据缓冲寄存器(数据端口)和一个设备状态寄存器(状态端口)。主机进行I/O操作时,先发出查询信号,读取设备的状态并根据设备的状态决定下一步操作是进行数据传输还是等待。
7.3.2中断方式
前言:异常和中断机制
7.3.2.1基本概念
7.3.2.2工作流程
- 中断请求:中断源向CPU发送中断请求信号。
- 中断响应:CPU具备响应中断的条件,并进行中断判优,即,当多个中断源同时提出请求时通过中断判优逻辑响应一个中断源
- 中断处理:转入中断服务程序。
1.中断请求
通过INTR线发出的是可屏蔽中断,通过NMI线发出的是不可屏蔽中断。可屏蔽中断的优先级最低,在关中断模式下不会被响应,而不可屏蔽中断用于处理紧急和重要事件,如时钟中断、电源掉电等,其优先级最高,其次是内部异常,即使在关中断模式下也会被响应。
注:I/O设备的就绪时间是随机的,而CPU在统一的时刻即每条指令执行阶段结束前向接口发出中断查询信号,以获取I/O的中断请求,也就是说,CPU响应中断的时间是在每条指令执行阶段的结束时刻。这里说的是中断仅指I/O中断,内部异常不属于此类情况。
2.中断响应判优
中断优先级包括中断响应优先级和处理优先级,响应优先级在硬件线路上固定,不便改动。处理优先级可利用中断屏蔽技术动态调整,以实现多重中断。
响应优先级是指CPU响应中断请求的先后顺序。
3.中断响应过程
中断隐指令并不是一条具体的指令,而是CPU在检测到中断请求时自动完成的一系列动作,这些操作由硬件直接实现。
注意异常和中断的差异:异常指令通常没有执行成功,异常处理后要重新执行,故其断点是当前指令的地址,中断的断点则是下一条指令的地址。
引出中断服务程序前需先识别中断源,才能将对应的服务程序入口地址送入程序计数器PC,有两种方法识别中断源:
- 软件查询法(非向量中断):CPU设置异常状态寄存器记录异常原因,操作系统使用统一的异常或中断查询程序,按优先级查询异常状态寄存器,查询到后立即转入内核中相应的处理程序。
- 硬件向量法(向量中断):异常或中断处理程序的首地址称为中断向量,所有中断向量被存放在中断向量表中(将系统中所有中断向量集中到存储器的某个区域,称为中断向量表)。在中断向量表中,每个异常或中断都被指定一个中断类型号,在中断向量表中,类型号和中断向量一一对应,可根据类型号快速判断。
中断向量地址形成部件的输入来自中断判优排队器的输出(中断类型号),而其自身输出的是中断向量地址,每个中断都有一个唯一的类型号,每个中断类型号都对应一个中断服务程序。CPU响应中断后,通过识别中断源获得中断类型号,然后据此计算出对应中断向量的地址,再根据此地址从中断向量表中取出中断服务程序的入口地址,并送入PC,以转而执行中断服务程序,这种方法称为中断向量法,采用中断向量法的中断称为向量中断。
7.3.2.3多重中断
注:中断处理优先级是指多重中断的实际优先级处理次序,可利用中断屏蔽技术动态调整,若不使用中断屏蔽技术,则处理优先级和响应优先级相同。
7.3.3DMA方式
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)