PC寄存器
背景
- 有了时钟信号,可以提供定时输入。有了D型触发器,可以在时钟信号控制的时间点写入数据
- 把这两个功能组合起来,就可以实现一个自动计数器
程序计数器
-
加法器的两个输入,一个始终设置成1,另外一个来自于一个D型触发器A
-
把加法器的输出结果,写到这个D型触发器A里面。于是,D型触发器里面的数据就会固定的时钟信号为1的时候更新一次
-
这样,就有了一个每过一个时钟周期,就能固定自增1的自动计数器
-
这个自动计数器,可以拿来当PC寄存器,事实上,PC寄存器的这个PC,英文就是Program Counter,也就是
程序计数器
的意思
作用
- 每次自增之后,可以去对应的D型触发器里面取值,也是下一条需要运行指令的地址
- 同一个程序的指令应该要顺序存放在内存里面。顺序存放指令,就是为让我们通过程序计数器就能定时不断执行新指令
单指令周期处理器(Single Cycle Processor)
- 加法计数,内存取值,乃至后面的命令执行,最终其实都是由一开始讲的时钟信号,来控制执行时间点和先后顺序,也是需要时序电路最核心的原因
- 在最简单的情况下,需要让每一条指令,从程序计数、到获取指令、执行指令,都在一个时钟周期内完成
- 如果PC寄存器自增太快,程序就会出错
- 因为前一次的运算结果还没有写回对应的寄存器里面的时候,后面一条指令已经开始读取里面的数据来做下一次计算了
- 这个时候,如果我们的指令使用同样的寄存器,前一条指令的计算就会没有效果,计算结果就错了
- 在这种设计下,需要在一个时钟周期里,确保执行完一条最复杂的CPU指令,也就是耗时最长的一条CPU指令
- 这种的CPU设计,称之为
单指令周期处理器(Single Cycle Processor)
- 这种的CPU设计,称之为
- 缺点
- 很显然,这样的设计有点儿浪费
- 因为即便只调用一条非常简单的指令,也需要等待整个时钟周期的时间走完,才能执行下一条指令
2 - 1 选择器(译码器)
背景
- 数据能够存储在D型触发器里,如果把很多D型触发器放在一起,就可以形成一块很大的存储空间,甚至可以当成一块内存来用
- 那我们怎么才能知道,写入和读取的数据,是在这么大的内存的哪个几个比特?
- 这个需要一个电路,来完成"寻址"的工
电路构成
-
通过一个反向器、两个与门和一个或门,就可以实现2-1选择器
-
通过控制反相器的输入是0还是1,能够给决定对应的输出信号,是和地址A,还是地址B的输入信号一致
-
一个反向器只能有0和1这样两个状态,所以只能从两个地址中选择一个
- 如果输入的信号有三个不同的开关,就能从 2 ^ 3,也就是8个地址中选择一个,这样的电路,叫
3 - 8译码器
- 如果CPU是64位,就意味着寻址空间也是2 ^ 64,那么就需要一个有64个开关的译码器
- 如果输入的信号有三个不同的开关,就能从 2 ^ 3,也就是8个地址中选择一个,这样的电路,叫
作用
-
其实,译码器的本质,就是从输入的多个位的信号中,根据一定的开关和电路组合,选择出自己想要的信号
-
除了能够进行“寻址”之外,还可以把对应的需要运行的指令码
-
同样通过译码器,找出我们期望执行的指令,也就是在之前讲到过的opcode,以及后面对应的操作数或者寄存器地址,只是,这样的“译码器”,比如2-1选择器和3-8译码器,要复杂得多
建立数据通路,构造一个最简单的CPU
图例
实现
- 首先,有一个自动计数器
- 这个自动计数器会随着时钟主频不断自增,来作为我们的PC寄存器
- 在这个自动计数器的后面,连着一个译码器
- 译码器,还要同时连着大量的D触发器组成的内存
- 自动计数器会随着时钟主频不断自增,从译码器中,找到对应的计数器所表示的内存地址,然后读取出里面的CPU指令
- 读取出来的CPU指令会通过我们的CPU时钟的控制,写入到一个由D型触发器组成的寄存器,也就是指令寄存器当中
- 在指令寄存器后面,可以再跟一个译码器
- 这个译码器不再是用来寻址的了,而是把我们拿到的指令,解析成opcode和对应的操作数
- 当我们拿到对应的opcode和操作数,对应的输出线路就要连接ALU,开始进行各种算术和逻辑运算
- 对应的计算结果,则会再写回到D触发器组成的寄存器或者内存当中
条件寄存器
- 讲计算机的指令执行的时候,高级语言中的 if…else,其实是变成了一条 cmp 指令和一条 jmp 指令
- cmp 指令是在进行对应的比较,比较的结果会更新到条件码寄存器当中
- jmp 指令则是根据条件码寄存器当中的标志位,来决定是否进行跳转以及跳转到什么地址
- 为什么if…else 会变成这样两条指令,而不是设计成一个复杂的电路,变成一条指令?
- 两个指令实现,完全匹配好了我们在电路层面,“译码 - 执行 - 更新寄存器“这样的步骤
- cmp 指令的执行结果放到了条件码寄存器里面,我们的条件跳转指令也是在 ALU 层面执行的,而不是在控制器里面执行的
- 这样的实现方式在电路层面非常直观,我们不需要一个非常复杂的电路,就能实现 if…else 的功能
单指令周期处理器的优化
背景
- 在上面的抽象的逻辑模型中,你很容易发现,我们执行一条指令,其实可以不放在一个时钟周期里面,可以直接拆分到多个时钟周期
- 因为从内存里面读取指令时间很长,所以如果使用单指令周期处理器,就意味着我们的指令都要去等待一些慢速的操作
- 这些不同指令执行速度的差异,也正是计算机指令有指令周期、CPU 周期和时钟周期之分的原因
案例
- 可以在一个时钟周期里面,去自增 PC 寄存器的值,也就是指令对应的内存地址
- 然后,我们要根据这个地址从 D 触发器里面读取指令,这个还是可以在刚才那个时钟周期内
- 但是对应的指令写入到指令寄存器,我们可以放在一个新的时钟周期里面
- 指令译码给到 ALU 之后的计算结果,要写回到寄存器,又可以放到另一个新的时钟周期
- 所以,执行一条计算机指令,其实可以拆分到很多个时钟周期,而不是必须使用单指令周期处理器的设计
- 因此,现代我们优化 CPU 的性能时,用的 CPU 都不是单指令周期处理器,而是通过流水线、分支预测等技术,来实现在一个周期里同时执行多个指令
问题
- CPU在执行无条件跳转的时候,不需要通过运算器以及ALU,可以直接在控制器里面完成,你能说说这是为什么吗?
- 无条件跳转意味着没有计算的逻辑,应该是可以不经过ALU的,但是要控制器把PC设置成跳转后的指令地址