一、实验目的:
通过设计并实现支持10 条指令的CPU,进一步理解和掌握CPU 设计的基本原理和过程。
二、实验内容:
设计和实现一个支持如下十条指令的单周期CPU。
Ø非访存指令
u清除累加器指令CLA
u累加器取反指令COM
u算术右移一位指令SHR:将累加器ACC 中的数右移一位,结果放回ACC
u循环左移一位指令CSL:对累加器中的数据进行操作
u停机指令STP
Ø访存指令
u 加法指令ADD
u 存数指令STA
u 取数指令LDA
Ø转移类指令
u 无条件转移指令JMP imm:signExt(imm) -> PC
u 有条件转移(负则转)指令BAN X: ACC 最高位为1 则(PC)+ X -> PC,否则PC 不变
三、实验原理
1、约定机器字长、指令字长和存储字长均为16位。
2、约定指令格式如下图所示,高4位为指令的操作码字段,低12位为指令的地址码或者立即寻址的操作数。
3、指令和相应的操作码对照表
CPU 原理图
四、实验步骤
4.1 CPU 各模块Verilog 实现
1) PC 模块
输入 |
时钟信号clk、重置信号 rst 、停机信号stop、无条件转移信号wr、条件转移信号judge、 pc修改量jmp(12位) |
输出
|
指令地址addr(12 位) |
功能 |
每个时钟上升沿 addr 的值自动加 1,并输出 如果wr为1,修改addr为 jmp - 1 如果judge为1,修改addr为 addr + jmp 如果rst为1,修改addr为0
|
Verilog 关键代码:
2) 指令存储器模块
该模块中已经初始化了10条指令,并且刚好串在一起,可以作为一组逻辑统一的整体。
输入 |
12位指令地址 addr |
输出 |
16 位指令 ins |
功能 |
存放待执行的指令(初始化),并根据地址输出指令 |
Verilog 关键代码:
3) 累加器
输入 |
时钟信号clk、读写控制线 wr、输入数据 indata |
输出 |
输出数据outdata |
功能 |
ACC数据从outdata输出,如果wr有效,在clk下降沿将会把indata写入ACC中。 |
Verilog 关键代码:
4) ALU
表4.4 ALU 模块功能描述
输入 |
操作数 in1 和in2、操作选择信号alu_op |
输出 |
ALU 运算结果 Z
|
功能 |
根据操作选择信号计算in1 和in2 的运算结果 Z |
Verilog 关键代码:
5) 控制单元
表4.5 控制单元模块功能描述
输入 |
指令(操作码) |
输出 |
停机信号stop、PC读写控制线 pcwr、ACC读写控制线 accwr 、数据存储器读写控制线 datamemorywr、ALU 的操作选择信号 op |
功能 |
根据当前指令功能对stop、pcwr、accwr、datamemorywr和op 赋值 |
Verilog 关键代码:
6) 数据存储器模块
该模块中初始化了2条数据,一个用于测试各种运算功能,另一个用于测试条件转移。
输入 |
时钟信号clk、读写控制线wr、12位指令地址 addr、输入数据 indata |
输出 |
16 位输出数据 outdata |
功能 |
存放数据,可以读出,或在clk下降沿写入。 |
Verilog 关键代码:
4.2 CPU 顶层文件封装实现
在这个文件中,声明了pc,insmemory,datamemory,acc,cu,alu等模块。
并且声明了几个wire类型的变量用于连接各个部件。
Verilog 关键代码:
4.3 CPU 模拟仿真
1、TestBench关键代码
CPU的测试文件如下,主要功能就是产生了时钟信号,并且使用rst信号初始化pc。
clk信号每1ns反转一次,一个时钟周期2ns。
20ns后结束测试,刚好测试完10条指令。
2、ModelSim仿真及分析
指令1 LDA 取数指令
这条指令在指令存储器的地址000000000000处。传送给ALU的命令是0110。
将数据地址为000000000000处的数据0000000000000010存储进ACC中。
CU会向ACC发出写信号,在时钟的下降沿写入数据。
指令2 COM 取反指令
这条指令在指令存储器的地址000000000001处。传送给ALU的命令是0001。
将ACC中的数据0000000000000010取反后得到1111111111111101。
CU会向ACC发出写信号,在时钟的下降沿写入数据。
指令3 SHR 算数右移指令
这条指令在指令存储器的地址000000000010处。传送给ALU的命令是0010。
将ACC中的数据1111111111111101算数右移后得到1111111111111110。
CU会向ACC发出写信号,在时钟的下降沿写入数据。
指令4 CSL 循环左移指令
这条指令在指令存储器的地址000000000011处。传送给ALU的命令是0011。
将ACC中的数据1111111111111110循环左移后得到1111111111111101。
CU会向ACC发出写信号,在时钟的下降沿写入数据。
指令5 CLA 清除指令
这条指令在指令存储器的地址000000000100处。传送给ALU的命令是0000。
将ACC中的数据1111111111111101清零后得到0000000000000000。
CU会向ACC发出写信号,在时钟的下降沿写入数据。
指令6 ADD 加法指令
这条指令在指令存储器的地址000000000101处。传送给ALU的命令是0100。
将ACC中的数据0000000000000000和数据存储器的地址为000000000001处的数据相加得到1000000000000000再保存到ACC中。
CU会向ACC发出写信号,在时钟的下降沿写入数据。
指令7 STA 存数指令
这条指令在指令存储器的地址000000000110处。传送给ALU的命令是0101。
ACC中的数据存储到数据存储器地址为000000000010的单元。
可以从图中看到000000000010单元的值由不确定变为1000000000000000。
CU会向数据存储器发出写信号,在时钟的下降沿写入数据。
指令8 JMP 无条件转移指令
这条指令在指令存储器的地址000000000111处。传送给ALU的命令是1111。
这条指令使用地址码采用立即寻址方式向PC传送跳转的目标地址。
这里我们跳转到指令存储器地址为000000001001的单元(该单元保存了条件转移指令)。
可以看到下降沿的时候PC的值被修改为000000001000而不是000000001001,因为下一个时钟周期上升沿PC自动加1会进行修正。
CU会向PC发出写信号,在时钟的下降沿写入数据。
指令9 BAN 条件转移指令
这条指令在指令存储器的地址000000001001处。传送给ALU的命令是0111。
这里我这条指令设置为会判断ACC最高位是否位1,如果为1,会把PC增加2。
注意这里不需要进行PC的修正,直接在下降沿将PC加2修改000000001011。
因为在相对寻址中,位移量是以条件转移指令的下一条指令的地址为基准的做偏移的。
而指令字长刚好是一个存储字,所以最终会跳转到地址为000000001100的指令存储器单元。该单元内的指令为停机指令。
ALU会根据判断的结果向PC发出写信号judge,如果为1,在时钟的下降沿修改PC。
指令10 STP 停机指令
这条指令在指令存储器的地址000000001100处。传送给ALU的命令是1111。
这条指令会将PC内的标志位state设置为0。
如果state为0的话,PC在每个时钟上升沿将不会自动加1。
在图中可以看到下一个时钟上升沿到来的时候,地址保持000000001100无变化。
CU会向PC发出停机信号STOP,使PC不再自动增加。
五、总结
Verilog语法简洁优雅大方,给人以美的享受。
譬如CU中的这一段关键代码,既滴水不漏地实现了功能,还十分简洁。