文章目录
CPU的基本结构
运算器的基本组成
控制器的基本组成
CPU的功能
控制器和运算器的功能
运算器的基本结构
数据通路:数据在功能部件之间传送的路径。
专用数据通路方式
CPU内部单总线方式
ALU的两个输入端一定要等到两个输入的信号(0101…)稳定之后,这一次的运算才有可能得到正确的结果,然而例如:其中的一个数据来自于R0,R0给的这个输入信号不稳定之前,ALU就会产生一个输出信号送到内部总线上,这时就会和R0输出到ALU时内部总线上的信号发生冲突,这就会导致运算的错误。
解决办法:在ALU的输出端再加上一个【寄存器】,这样的话,当R0输入到ALU的信号稳定之后,ALU会先将运算结果放到【暂存寄存器】当中,在【暂存寄存器】上面会加一个【三态门】,等ALU的输出结果稳定之后,再让这个【三态门】导通,从而把运算结果送到【内部总线】上,然后再给R0的输入端R0in接上一个有效的电信号R0in=1,就可以把这个加法运算的结果输入回R0中
为了方便一些复杂运算结果的实现,【暂存寄存器】还可以增加一些功能:比如把他改成【移位寄存器】or【累加寄存器】
【程序状态字寄存器】:我们在进行运算的时候,ALU每进行一次运算,这一次运算结果的状态信息都会被记录在PSW这个寄存器当中
【计数器】:二进制的乘除法,本质上就是进行多次的加减法,通过计数器来记录到底执行了多少次的加减法
控制器的基本结构
用户是否可见
橙色是用户可见;灰色是用户不可见
为什么是用户可见:PC:因为用户可以通过(无)条件转移指令来改变PC的值
PSW:对于某些条件转移指令,本身就需要使用到psw
ACC:用户执行加法、乘法,都会改变ACC的值
通用寄存器:程序可以通过汇编语言直接读和写这些通用寄存器里面的值
PC的位数取决于存储器的字数
指令寄存器(IR)用于接收取得的指令,取决于指令字长
指令执行过程
指令周期
指令周期流程
CPU通过设置触发器,来确定当前处于哪一个时钟周期
取址
取址周期:要把指令从主存中取出来:
- 根据PC的指向,先把这条指令的地址部分放入MAR,然后把地址信息通过地址总线送给主存
- CU控制单元发出读命令R=1,这个读命令的信号通过控制总线发出
- 通过上面两步,主存通过地址总线知道了要操作的地址,同时,通过控制总线知道了要对这个地址进行读操作
- 接下来,主存就将我们要取出的指令,把它通过数据总线传送给MDR,再把MDR中取得的这条指令放入IR中
- 每次取出一条指令,PC都要自动加“1”
间址
间址周期:
- 先将指令寄存器IR当中的保存的形式地址的字段EA放到MAR中,再通过地址总线送到主存
- 同时,CU通过控制总线向主存发出读信号
- 主存收到读命令之后,就将Ad(IR)中这个地址所保存的数据通过数据总线放入MDR中
注意:
在间址周期中,形式地址有时并不是从IR中取出的,而是直接从MDR中取出Ad(MDR),因为我们在取址间段,是把我们的数据先存放到MDR,再把MDR中的数据转存到IR中,所以在间址周期,MDR中依然保存了这个指令的完整数据,因此也可以用Ad(MDR)取出形式地址
中断
在每个程序or进程运行的过程当中,操作系统都会给运行的程序在内存中开辟一块堆栈空间,堆栈指针SP会指向栈顶元素。实际当中,堆栈空间的的地址是从上到下,由高地址–>低地址,也就是说,栈顶指针是指向【低地址部分】
也就是说,如果要把PC的值压入栈中,就要先把SP的值向下移动一格,
中断周期
- CU控制器将SP(堆栈指针)减1,SP指向了主存当中的栈顶。将SP指向的地址送入MAR中,【注意:SP记录了PC保存的地址(这时候pc还不没有写入栈顶),所以之后要把SP的值送入MAR】
- CU发出写命令,通过控制总线发送给主存
- 保存PC的值:把PC的值送入MDR,在通过数据总线传送到主存
- 有了要写入的数据PC值,给了写命令,同时也把要写入的地址也放入了MAR当中了,那么,当前执行的断点PC就可以压栈保存了
- 接下来,CU就可以修改PC的值,让程序的执行流转到中断服务程序的入口地址
指令执行方案【流水线】
数据通路的功能和基本结构(超级重点)
数据通路的基本结构:
- CPU内部单总线方式
- CPU内部多总线方式
- 专用数据通路方式
单总线结构
- Bus:总线
- 所有的in、out信号都是由CU发出的,所有底层都会与CU有连线
- PC指明了我们要读取的数据所存放的地址,所以刚开始,要把PC的值放到MAR当中
- PC传送完毕之后,撤销PCout和MARin信号,让总线空闲
- CU通过控制总线向主存发出读信号。那么主存就知道我要进行的是读操作
- 读操作的地址存放在MAR当中,通过【地址总线】传送给主存。主存根据MAR所保存的地址读出主存中对应地址的数据,然后通过【数据总线】传送到MDR
- 将MDR的数据再传送到IR【因为功能就是读取一条指令】
- 将IR的地址码部分传入到MAR
- CU向主存发出一个读命令
- 从主存中取出操作数并且传入MDR
- 将其中一个操作数放入【暂存寄存器Y】当中
- 另外一个操作数放在了【累加寄存器ACC】当中
- 将ACCout和ALUin接通,在ALU中计算出结果
- ((R0)):意思就是说R0存放了一个主存的地址,然后根据这个地址再从主存中取出这个地址所保存的数据
- (R1):表示把R1里面存放的数据取出来
- (R0):表示将计算的结果存到R0所指向的存储单元当中 【注意并不是写回R0】
任何一条指令的【取指周期】都是相同的,都是公共的
只要我们取出了当前的指令,那么这个PC的值就可以加1
- 先将寄存器中存放的地址传入MAR
- 通过MAR中的地址向主存读取数据,存入MDR
- 将MDR中保存的这个操作数存入寄存器Y
- 先把计算的结果存入寄存器Z
- 再将Z中的结果存入R0所指向的主存单元中。所以先把Z中加法的结果放回MDR中
- 将MDR总的数据再写入主存,此时,需要CU发出写命令
在间址周期,已经将R0的内容写入了MAR中了,并且MAR中的数据还没有更新过。
所以将MAR中的值传入主存,指明要写入的地址。
专用数据通路方式
- 先将PC的值传入MAR
- 将MAR的值通过外部的地址总线传入主存
同时向主存发送一个【读信号】
主存收到地址,收到读信号,就可以读取数据了- 主存将读取的信号通过外部的数据总线传入MDR
- 接下来这条指令要执行之前,还要送到IR
- 每取出一条指令都要让PC+1
- 把指令的操作码部分放入CU进行【译码】
- ALU运算器没有存储数据的功能,数据来自于ACC
- ALU支持将一个数据原封不动的传出去,类似于【中转站】
ALU不是寄存器- 对于存数据
ACC将数据传入MDR,
再将MDR中保存的数据,传入MAR保存的地址所指向的主存单元中
- 将主存地址存入MAR中
- 把加法得到的结果ACC中的数据传入MDR中
- 再将MDR中保存的数据,传入MAR保存的地址所指向的主存单元中
控制器的功能和工作原理
- 指令执行的过程中,在一个机器周期内我们需要通过若干个【微操作序列】来完成,那一个机器周期又会有若干个【时钟周期】组成,每个时钟周期又可以称为一个【节拍】,会在每一个节拍内发出一个所谓的【微命令】,用来完成对应的微操作。
- 所谓的微命令指的就是与这个微操作所对应的控制信号。
- 取指周期、间址周期、中断周期内所需要做的这些微操作,所有的指令都是一样的。
只有执行期内所需要做的这些微操作序列可能会出现一些区别- 设计控制器的核心思想
但是只要我们能够知道指令的【操作码】能够判断这条指令的具体类型,那么我们也能够确定这条指令的执行周期内每个节拍需要完成哪些微操作,因此只要我们能够确定指令的操作码,并且再根据这几个【触发器】的信息来判断当前到底处于哪一个机器周期,另外再结合上【节拍信号】就是T0,T1,T2,也就是目前我们处于这个机器周期内的第几个节拍。最后再结合上【机器状态条件】,就比如说psw里边记录的什么溢出等这些状态条件结合这四个维度的信息,我们就可以确定现在所处的这个节拍下应该发出哪些命令,因为每个命令都是和微操作一 一对应的。
硬布线控制器
- 指令执行的过程中,在一个机器周期内我们需要通过若干个【微操作序列】来完成,那一个机器周期又会有若干个【时钟周期】组成,每个时钟周期又可以称为一个【节拍】,会在每一个节拍内发出一个所谓的【微命令】,用来完成对应的微操作。
- 所谓的微命令指的就是与这个微操作所对应的控制信号。
- 取指周期、间址周期、中断周期内所需要做的这些微操作,所有的指令都是一样的。
只有执行期内所需要做的这些微操作序列可能会出现一些区别- 设计控制器的核心思想
但是只要我们能够知道指令的【操作码】能够判断这条指令的具体类型,那么我们也能够确定这条指令的执行周期内每个节拍需要完成哪些微操作,因此只要我们能够确定指令的操作码,并且再根据这几个【触发器】的信息来判断当前到底处于哪一个机器周期,另外再结合上【节拍信号】就是T0,T1,T2,也就是目前我们处于这个机器周期内的第几个节拍。最后再结合上【机器状态条件】,就比如说psw里边记录的什么溢出等这些状态条件结合这四个维度的信息,我们就可以确定现在所处的这个节拍下应该发出哪些命令,因为每个命令都是和微操作一 一对应的。
- 我们想要确定当前这个节拍下控制单元CU应该发出什么样的微命令,那么我们首先需要参考的是【指令的操作码】,因为不同的指令在执行阶段所需要做的微操作序列是不一样的好,所以我们首先需要把【指令寄存器IR】的操作码,送给【操作码译码器】。
- 还需要知道当前这个指令的【目前机器周期】,因此我们还需要把四个【触发器】的二进制信息把它送给CU,CU可以根据当前这几个触发器的值哪一个值为1,用这样的方式来判断目前处于哪个机器周期好,所以这样我们就得到了第二个需要的信息。
- 我们还需要让cu能够判断出当前处于这个机器周期内的【第几个节拍】,所以我们还需要给CU输入一个【节拍信号】,那节拍信号是通过一个所谓的【节拍发生器】来给出的。看这个图不难理解,就是我们的时钟部件会有规律的发出这种脉冲信号,每个【脉冲信号】就是一个【时钟周期】,那么这个节拍发生器接收到时钟部件发来的脉冲信号之后,他都会选择让其中的某一根输出线让它导通,比如一个脉冲让T0输出一个高电平,然后第二个脉冲让T2输出一个高电平,然后第三个,第四个以此类推,那这样的话CU就可以根据这些线每根线输入了高电平信号,用这个信息来判断当前是处于第几个节拍。那之前我们是规定了我们要采用定长机器周期,一个机器周期所包含的节拍数都是相等的,那对于这个图来说,相当于每一个机器周期会包含m+1个节拍,从T0到Tm总共m+1个节拍,那这些节拍信号是循环的发出的,也就是说如果此时已经到达了当前这个机器周期的最后一个节拍,发出这个节拍信号,接下来如果再接收到下一个脉冲信号,那么下一个节拍信号又会回到t0,那这也就意味着我们进入了下一个机器周期,所以这就是用节拍发生器来表示目前的节拍信号的一个原理。
- 最后我们还需要给CU提供一个输入的信息,也就是【机器的状态条件】。我们把所有的这些标志来自于执行单元,比如说我们之前说过的运算器里边会包含PSW还有ACC,那PSW里边会包含某一些很关键的信息位,比如说是否有溢出或者运算结果为正还是为负,有可能会影响到接下来的这个微操作序列的一个执行,那除了PSW之外,有可能会需要根据ACC累加寄存器里边存放的这个数的符号就是正负性之类的,这个信息也有可能会影响到接下来的操作序列的一个执行流。那除了来自运算器之外,也有可能会有来自io设备,还有来自于储存的一些反馈信号,也可能会影响到接下来的一个微操作执行流,所以这些标志信息也需要输入给控制单元。
- 那接下来就可以根据这四组的信息来决定当前这个节拍下。
所以控制单元CU它的输出就是对应一系列的微命令,那么每一条输出线就对应着一个微命令,也就是对应着一个微操作,比如说如果我们想要让C1这个输出让他对应PC传到要对用这样的一个为操作那么我们只需要把C1这边输出线把它接到PCout和MARin就可以。
硬布线控制器的设计
- 对于PC+1这个微操作,,只要我们把PC的值放入MAR,那么我们就可以让pc的值加一了,所以这种微操作,我们只需要让他在第一个微操作之后就可以。不一定把它放到最后面,好,那我们可以把它放到三这类的操作的后面。
- 第二个微操作它的控制对象是主储存器,而第一个被操作,它的控制对象是两个具体的CPU内部的寄存器,所以这两个微操作中显然可以把他们安排在同一个节拍上完成,只要存储器此时空闲,那么就可以发出与第二个的操作所对应的微指令
4和5这两个微操作,由于这两个微操作他们执行时间都很短,所以在一个时钟周期内,我们能够保证这两个微操作,所以虽然他们之间有前后的依赖关系,但是我们同样可以把他们安排在一个节拍的完成,因此在t2这一节拍拍可以完成4和5这两个微操作。- 3和4【不可以】在一个节拍内完成
原因在于3这个操作我们需要从主储存器当中读取数据,而从储存器中取得一个数据的用时是比较长的,因此我们必须使用一个时钟周期才可以保证我们能够从储存器当中读到这个数据,因此我们不能把3和4这两步安排在同一个节拍内
1和2被控对象不同,所以可以安排在一个节拍内
3需要访存,需要单独的一个节拍
4再用一个节拍
非访存指令:一定没有间址周期
访存指令:可能有间址周期
组合逻辑设计
- 填上1,表示这条指在取址阶段的T0节拍内是需要进行这两个微操作的
- T2节拍的后两行,I(爱)与I取反,当状态为I时,就需要把1放入IND这个触发器中,表示接下来要进入间址周期。
当状态为I取反时,就把1传入EX这个触发器中,表示接下来直接进入执行周期
- 对于这些非访存指令,他们都不会进入间址周期
- 当我们进行间接寻址的时候,有可能进行多级的间接寻址。
所以只有当IND取反等于1的时候,说明间址周期已经完毕,所以把1传递给触发器EX,接着才可以进入执行周期,
将各种指令分别在每一个节拍内执行的微操作都整合在对应的节拍内
- 加号(+)表示或
IND·T 1 (ADD+STA+LDA+JMP+BAN):表示此时执行的是间址周期的第一个节拍,并且是括号中这几种指令的其中一种就执行M(MAR)→MDR这个一个特点微操作命令
微程序控制器
我们用高级语言写的代码,会被翻译成一系列与之对等的机器指令,每一条机器指令又会被翻译成几条微操作,由微操作序列来完成这条指令的具体功能
五段式流水线
IF:取值
M:访存
WB:写回
为了保证每个阶段都满足最长耗时。需要在每个功能段部件后面添加一个【缓冲寄存器】
Instruction decode指令译码阶段,在这个指令译码阶段除了完成指令译码的工作之外,还会完成取数的操作。取数就是只要把这条指令所需要用到的操作数从【通用寄存器】里边把它取出来,然后放到这个锁存器a和b里边。那这点又和我们之前学习的的指令不太一样,之前我们学习的指令,比如说【加法指令】可以直接指明我要访问的哪个加数或者被加数是来自于主存。这个操作所需要用的操作数会直接来自于主存,这是我们之前介绍过的那些指令,但是在这种【RISC经典指令集】的系统之下,我们想要进行运算的操作数一定是【直接来自于】通用寄存器的。不可能直接来自于主存,如果一个来自于主存,那么一定需要先把那个数据先放到通用寄存器,然后再从通用寄存器当中取出那个数据,所以这个地方能译码的阶段,除了指令译码之外,还会从通用寄存器里边取出当前这一条指令所需要用的操作数,会把它放到a和b这两个锁存器里边,然后接下来第三个阶段。
imm寄存器:是一个立即数寄存器。用于存立即数的,因为我们有的指令当中可能会使用立即寻址,就是指令的地址码部分就直接说明了一个立即数,那么在这种情况下,我们可以直接从指令当中取出接下来执行阶段所需要使用的立即数,把它放到这个锁存器里边,所以有的时候啊第三个阶段就是执行阶段处理的数据,有可能一个是立即数,另一个是来自于某一个通用寄存器
ID有可能对通用寄存器进行读的操作
WB有可能要对通用寄存器进行写的操作
这两个阶段对通用寄存器的读和写就有可能造成一些问题
IF和M都需要进行访存的操作
这两个阶段所需要访存的数据一定是不相同的
IF阶段访问的是指令数据
M阶段是访问的是变量之类的其他数据
流水线的表示方法
指令流水线的性能指标
装入时间:第一条指令从址到结束所需要的时间
排空时间:最后一条指令从取值到结束所需要的时间
加速比:说明引入流水线之后,比之前快了K倍
可以通过移动填补的方式计算不规则区域的面积
影响流水线的因素
五段式流水线总结
流水线的分类