前言
昨天复(yu)习了:计组复习(一):乘法器,除法器与浮点加法器,巩固了硬件事如何实现运算操作的。
今天复习 cpu 数据通路,也是很复杂的图。一步一步来吧。
唔。。。。现在是凌晨 1:42,人快芜了,所以博客内容可能会出现一些纰漏 dbq 我爬 Orz
才不是打了一天 lol 导致没时间复习。还有,有没有懂哥知道男刀这版本怎么玩?出暗爪还是幕刃还是渴血?征服者 or 电刑?
编辑下:我的我的 还真漏了。。。
课本上的图有一个多路复用器 01 接口画反了,但是我所有图片都是按照课本的图描图画的,于是也反了,来不及改了,算了(摆烂
就是 Jump 控制信号对应的复用器:
Jump 为 1 时才使用 Jump 的跳转,否则使用 beq 或者 PC+4 作为下一条指令地址。
单周期数据通路
单周期即一个指令的执行,不包括流水线并行,是一种简单(雾)的数据通路。由之前的学习知晓 mips 的指令也分为几个阶段:
- 取指令 IF
- 译码 ID
- 执行 EX
- 访问内存 MEM
- 写回 WB
硬件正是根据这几个步骤进行设计的,且看 cpu 如何实现。
按照惯例先上图,尽管这个图非常吓人,但是待会我们一步一步来分析它。
单周期数据通路的硬件从左到右对应了 mips 的 5 个阶段:
- 最左边首先是地址内存,对应取指令与译码阶段(IF / ID)
- 随后是寄存器文件和 ALU,对应执行阶段(EX)
- 再右边是数据内存,对应内存访问阶段(MEM)
- 最后是写回(RW)。
同样的,数据按照从左到右的顺序进行通路遍历,来啦来看就知道了↓
这里以 R 型指令举例。
算数逻辑指令(R 型指令)
算数逻辑指令一般指 add,and 这些指令。他们都是 R 型指令
注:
R 型指令一般指有三个操作寄存器的指令:
这意味着我们需要从两个源寄存器(rs,rt)读取数据,同时将结果写回目的寄存器(rd)。接下来看各个阶段的数据通路:
取指令阶段
首先是取指令阶段,将指令取给控制单元,同时 PC+=4,如下图:
IF 阶段不需要任何的控制数据。
译码阶段
然后是译码阶段,这里需要用到 RegDst 控制信号,以确定目的寄存器是哪个。因为 R 型指令和数据存取指令有着不同的目的寄存器:
通过 RegDst 置 1 控制信号(下图黄色箭头)指挥多路复用器(mux),我们取 [15-11] 作为目的寄存器:
执行阶段
然后是执行(EX)阶段,首先从寄存器中读取两个操作数并且传入 ALU。
此外,需要额外的控制信号(对应下图黄色箭头)来决定数据源是来自寄存器还是由指令给出的立即数给出。
值得注意的是,ALUOp 控制信号告诉 ALU 要执行何种运算,因为不同指令需要做不同的运算,比如 add 就是按位相加,and 就是按位与运算。
因为执行的是 R 型指令,这里 ALUSrc 置 0 来确保从寄存器中读取数据,而不是来自于立即数,如下图:
内存访问阶段
再然后是内存访问阶段(MEM),因为 R 型指令都是算数逻辑指令,不涉及内存访问,通过两个控制信号:
- MemRead,置 0,表示不需要从内存中读取数据
- MemWrite,置 0,表示不需要将数据写入内存
通过两个控制信号,直接跳过这个阶段(对应下图红色箭头绕路):
写回阶段
最后是写回阶段。这里需要两个控制信号:
- MemtoReg,置 0,表示写回到寄存器的数据不是从内存中来
- RegWrite,置 1,表示需要将结果写回寄存器
控制信号如下图黄色箭头所示:
下一条指令
最后需要完成指令的跳转,这里通过控制信号:
- Branch,置 0,表示不需要进行分支跳转
- Jump,置 0,表示这不是一条 j 指令,按照 beq 或者 PC+4 来跳转
注:图中 Jump 的复用器画反了。
于是 PC+4 的值被写回 PC,完成下一条指令的跳转,如下图:
注:
这不是 mips 流水线里面的一个阶段
这里单独写出来是因为不想把图画的太复杂,否则很难看清
事实上这应该发生在写回阶段,毕竟写 PC 也是一种写回(雾
内存访问指令
和上面的 R 型指令的推导过程类似,这里我就不画分解图了 dbp 我是懒狗我爬,但是大体思路都是一致的。
回想 mips 每一个阶段都需要 赣神魔 干什么,就能很快得出答案!
首先来看 lw 指令。lw 指令需要 4 个关键的控制信号置 1,他们分别是:
- MemRead:置 1,需要读取内存
- MemtoReg:置 1,需要将内存数据写回寄存器
- RegWrite:置 1,需要写寄存器
- ALUSrc:置 1,需要从指令立即数读取 ALU 运算数据
四个关键控制信号由黄色箭头标记,而红色箭头则表示了数据的流向,如下图:
再来看 sw 指令。sw 指令只需两个关键控制信号置 1 即可:
- ALUSrc:置 1,表示从立即数读取操作数
- MemWrite:置 1,表示要向内存中写数据
两个关键控制信号由黄色箭头标记,而红色箭头则表示了数据的流向,如下图:
分支跳转指令
分支跳转指令也需要两个关键控制信号,他们分别是:
- Branch:置 1,表示需要执行分支跳转
- Jump:置 0,表示这不是一条 j 指令,按照 beq 或者 PC+4 来跳转
注:图中 Jump 的复用器画反了。
看图:
一步一步来看,就是:
- 首先根据立即数,计算分支指令跳转的目的地址(由上图蓝色箭头表示),此外注意地址计算乘以 4,因为一条指令占 4 字节
- 然后 ALU 会判断读取的两个寄存器(rs,rt)是否相等
- 如果相等,则给出一个控制信号(上图橙色箭头),并且和 Branch 控制信号进行与运算,决定最终是否执行分支
- 执行 beq / PC+4,写回 PC
总结(重要⚠)
在了解了几种指令的数据通路概要之后,老师给出的真值表似乎不那么棘手了:
此外,附一张内鬼给的控制信号含义表:
主要记忆两个:
ALUSrc:为 0 表示第二个操作数来自寄存器 rt,为 1 表示来自立即数
RegDst:为 0 表示目的寄存器是 rt,为 1 表示目的寄存器号为 rd
此外,注意 ALUOp 是 2 bit 的控制信号,它告诉 ALU 该做什么运算,加 or 减:
控制信号真值表: