设计文档
Key Point: 数据通路,控制器及其连接
要实现的核心指令介绍
add,sub,lui,ori,lw,sw,beq,nop
数据通路的建立
名称 | 功能 | 简写 |
---|---|---|
程序计数器 | 输出当前指令所在地址 | PC |
下指令地址 | 计算下一指令所在地址并传递给PC | NPC |
寄存器堆 | 32 个 32 位寄存器 | GRF |
指令存储器 | 存储所有的指令 | IM |
数据存储器 | 充当内存存储数据 | DM |
扩展单元 | 进行位扩展运算 | EXT |
算术逻辑单元 | 进行各项基本运算 | ALU |
下面先对各数据通路进行分析,并在此过程中得到对控制器的需求
(在每个数据通路中都只考虑自己需要什么
!
输出的东西如何被使用
是其他数据通路考虑的事情!!)
PC
一个 32 位寄存器即可
输出引脚:输出当前指令所在地址,提供给IM
用于取指令
输入引脚:由NPC
算出的下一条指令地址
作为整个设备中最核心的时序逻辑,在PC层面其本质应为Moore机
在下一周期上升沿
才可输出下一PC
在输出PC以后,其他数据通路都基本呈现组合逻辑的形态,即时性进行输出内容的改变,即Mealy机
(ROM和GRF的写入操作还是要等下一上升沿的,但是关于其写入的各项信息都是即时性得到的)
当然,最后输出PC值的时候要再加上 3000
若用PC初始化3000的方法,在复位后PC还是会输出 0
NPC
下一指令的地址可能是PC+4
对于beq跳转
也可能是PC+4+sign_ext(imm_16 || 00)
对于j, jal跳转
还可能是PC[31:28] || imm_26 || 00
输入引脚:输入当前PC值,imm_16, imm_26
选择信号:br, zero, j
这里区分br和zero是有原因的。
详见zero产出地:ALU
输出引脚:下一条指令PC值
!!经后续分析,对于XXXAndLink指令,PC+4是被需要的,那就直接从NPC输出
NPC外部的连接也比较直白
具体分析:
控制信号的使用:
- 只有br和zero同时为1时才是成功beq跳转
- 鉴别出j,jal等才使用imm_26直接地址跳转
Tips: 由于jal指令为本人后续添加,因此选择了新增了MUX而不是改变原MUX
计算过程实现:简单的加法,移位,位扩展,位拼接运算
要注意位扩展一定是sign_ext,因此完全可以直接使用bit_sign_extender
IM
采用了4096*32bit的ROM 地址长度选项只需12位
!!ROM的地址以字为单位,因此PC要右移2位才能传给ROM
右移之后还需bit_extender到12位
(一定要先右移再extend,因为实质上就是取PC[13:2])
其余的没什么内容了
Splitter
把这个东西单独拿出来写只是图个方便()
Splitter内部的构造就只是一些小splitter
EXT
EXT也是一个相对好说的部件
根据EXTOp进行不同形式的位扩展
(缺点(?)是只能用于16bit -> 32bit)
EXTOp | 含义 |
---|---|
0 | 无符号扩展 |
1 | 符号扩展 |
EXTOp具体怎么得到就是Ctrl要考虑的了
外部构造:
内部结构:
好的我刚刚意识到bit_extender本来就可以输入EXTOp
但是我的EXT更好看(?)那就不改了
GRF
GRF相对来说就复杂多了
内部结构在P0课下已经搭好了,但其正确性仍需后续测试
在此仅略加展示:
而其外部结构也大有文章
指令 | 使用数据 |
---|---|
add,sub | 读rs,rt写ALU到rd |
ori | 读rs写ALU到rt |
lui | 写ALU到rt |
lw | 读rs(即base)求ALU写MemReadData到rt |
sw | 读rs(即base)求ALU但不写Grf |
beq | 读rs,rd求ALU(做减法判zero)但不写Grf |
jal | 不读但写PC+4到$31 |
因此构造相应的控制信号与多路选择器即可
Wrsel | 含义 |
---|---|
0 | 写到rt |
1 | 写到rd |
Wdsel | 含义 |
---|---|
0 | 写ALU的结果 |
1 | 写MemReadData |
后续添加的jal指令我又使用了控制信号Link
Link | 含义 |
---|---|
0 | 按上述两个选择器行事 |
1 | 写PC+4到$31 |
当然,除此之外还有最重要的写使能信号
整体外部结构如下图所示:
ALU
首先明确ALU要解决的问题:
加法,减法,或,左移16位共4种运算
显然ALUOp需要4种,即需要两位信号
ALUOp | 使用指令 |
---|---|
00 | add,加法 |
01 | sub,beq,减法 |
10 | ori,或运算 |
11 | lui,左移16位 |
不过,我并没有直接分四种器件进行操作
采用了gxp老师课上提到的方法:
加法和减法可使用同一加法器!!
a - b = a + ~b + 1
而两个数相加再加1正是加法器已经提供的功能!
最上方的接口即为进位接口
!但是复用器件的代价就是更多的选择信号
减法不仅仅要选择进位信号,还要选择参与运算的数
对于整个ALU还需要区分进行了什么运算
我们分为如下三个
使用指令 | M1 | M1含义 | Cin | Cin含义 | M2 | M2含义 |
---|---|---|---|---|---|---|
加法 | 0 | 使用b | 0 | 进位为0 | 00 | 加减 |
减法 | 1 | 使用~b | 1 | 进位为1 | 00 | 加减 |
或运算 | X | X | X | X | 01 | 或运算 |
左移16位 | X | X | X | X | 10 | 左移 |
如何根据ALUOp写出这些控制信号也一目了然:
只需把上面两个表合起来,让ALUOp直接对应控制信号
用Combinational Analysis给我们写出来就行了
最终内部结构如下:
在此解释前文NPC中zero与br都需存在的原因:
beq也是对rs,rt的值做减法,但关键在于结果值为0时输出zero信号为1
因此zero信号也是会被sub甚至add干扰的
所以在
zero==1
时必须有br==1
才有效另一方向显然,
br==1
时判跳转有效当然离不开zero==1
的判定
关于其外部连接,关键只是两个控制信号:
我们把GRF处使用的表格稍有侧重点地修改
指令 | 使用数据 |
---|---|
add,sub | rs,rt算ALU(加减) |
ori | rs,imm算ALU(或运算) |
lui | imm算ALU(移位) |
lw,sw | rs,imm算ALU(加法) |
beq | rs,rd算ALU(做减法判zero) |
将rs替换成RD1,将rt,rd按照对应法则替换到RD2
可得到更清晰的表格
指令 | 使用数据 |
---|---|
add,sub | RD1,RD2算ALU(加减) |
ori | RD1,imm算ALU(或运算) |
lui | imm算ALU(移位) |
lw,sw | RD1,imm算ALU(加法) |
beq | RD1,RD2算ALU(做减法判zero) |
即可发现控制信号除了ALUOp之外,还有操作数2的选择
操作数2可选择RD2或imm
因此构造相应的控制信号与多路选择器即可
Bsel | 含义 |
---|---|
0 | RD2 |
1 | imm |
这里的imm都是imm_16经过EXT的结果
事已至此,可以顺便EXTOp也考虑清楚
准确来说,只有ori需要无符号(EXTOp == 0
)
EXTOp | 指令 |
---|---|
0 | ori |
1 | lw,sw |
X | 其他 |
beq的sign_ext已经在NPC里面确认了
EXTOp对于beq指令没有意义
外部连接如下图所示:
DM
我们采用了3072*32bit的RAM 地址长度选项只需9位
DM和GRF逻辑类似
但是由于我们直接使用RAM
在一些内容的表达上需要按照RAM行事
- RAM 应使用双端口模式,即设置 RAM 的 Data Interface 属性为 Separate load and store ports
- RAM的ld也需要特别激活,因此需要一个lw信号来控制它
- str信号就是普通的写使能信号
- clr信号为异步复位信号
- 和ROM类似,RAM的地址也以字为单位,因此PC要右移2位才能传入
- 右移之后还需bit_extender到9位
(一定要先右移再extend,因为实质上就是取PC[10:2])
DM的A接口是地址,由ALU算出
要存入的信息则是GRF从rt读出来的RD2
连接比较简单
控制器的搭建
在数据通路的苦苦搭建之中,其实控制信号
已经都有了自己的定义
我们发现,这些定义一般都依赖于指令
那么控制器就可以建起这个桥梁:
通过opcode和funct得到指令
再由指令得出控制信号
由外部信号到指令
得到指令的过程我使用了比较器,因此构建过程非常简单
由指令到控制信号
由指令到控制信号那可就更简单了
除了 ALUOp()
我们使用OR阵列
哪条指令需要这个信号,我们就给它或
到这个控制信号上
这种拉线式的写法还是很方便的
ALUOp就只能拜托我们亲爱的Combinational Analysis啦
CTRL在整个main电路中的书写还是比较简单的
我把他设计成了一个很富有信息量的样子()
搭电路的过程中一些小惬意的时光就是在修改电路外观~
测试文档
那么至此,我们的基础版CPU算是实现了基本自洽
接下来,就需要有大量的边界与随机指令去测试它了!
我首先测试了课程组给出的附件,并翻译为MIPS
|
|
寄存器数据及跳转测试
// 本测试的不足之处在于支持了MARS不支持的错误运算 //如最大正数加1,最小负数减1,-1减最小负数等
|
|
检验方法
在保证sw无问题的前提下
将所有的敏感变量都及时存储
be like:
|
|
之后只需要直接比对MARS和DM的存储区即可