多周期54条CPU:计组课设:多周期54条MIPS指令CPU设计(含代码)_孔艺菲的博客-CSDN博客
单周期CPU源码:while-TuRe/Single-cycle-CPU31 (github.com)
单周期CPU指的是一个周期就能得出结果的CPU。
如何做到一个周期得出结果呢?
答案是巧妙地利用时钟上升沿和下降沿,将同步控制和异步控制相结合。
异步控制 PC~instruction~RsRt~reg.XY~alu.Res:instruction是根据PC异步变化的,即PC改变后立即取出新指令。解析instruction中的Rs、Rt、Rd是通过assign实现与instruction同时变化。从寄存器中读取数据这一操作是随地址异步变化的,得到RsRt后立即在通用寄存器中进行读取。ALU也是逻辑电路,在得到操作数后立即得到结果。
同步控制:fileout,RF_W:输出结果是在testbench模块中时钟上升沿发生的,PC是在CPU的Controller时钟上升沿增加的。
那么,我们如何建立模型实现单周期CPU呢?
首先,什么是MIPS指令?我们在用MIPS编程时,写的是汇编语言。但是计算机不能识别汇编语言,只能识别机器语言。MIPS编译器Mars就可以将汇编语言编译成机器语言。编译的依据就是下面的指令格式表。我们要做的就是根据这样一个32位的二进制序列做为指令完成它所描述的一系列操作。
所以,需要弄懂要实现的指令的结构。MIPS有R型指令(只在寄存器中操作的指令),I型指令(含有立即数immediate的指令)和J型指令(jump跳转指令)。每种指令有不同的格式,每条指令有不同的op和func码以区分。
指令执行流程:
指令ID解析
为提高可读性,需要将每条指令不同的op和func码和指令对应起来。
方法一:可设置31个变量,如wire add_,sub_等,代表是不是这条指令。优点是可读性高,缺点是不易在模块间传输。
方法二:可设置1个31位变量区分不同指令,如000000000000000000000000000001代表add,000000000000000000000000000010代表sub等。优点是便于传参,缺点是可读性较低,且增加指令不易。
可选择将CPU模块调用和controller写在一起避免模块传输(不过计算机真正设计是分开的),更好的方法是用方法二改进方法一,在模块传输是写一个31位变量接口funcID,并且使其每位分别代表一个指令。
地址解析
为在一个时钟周期得到结果,采用组合逻辑设计,故这些变量都要采用assign赋值。对于不同种类的指令需调整如何赋值,根据指令ID通过?:实现。
指令格式
模块设计
计算机的基本组成:
- 存储器: 实现记忆功能的部件用来存放计算程序及参与运算的各种数据
- 运算器: 负责数据的算术运算和逻辑运算即数据的加工处理
- 控制器: 负责对程序规定的控制信息进行分析,控制并协调输入,输出操作或内存访问
- 输入设备: 实现计算程序和原始数据的输入
- 输出设备: 实现计算结果输出
我们主要需要实现的是前三项。
存储器有数据存储器和指令存储器,分别构建module DMEM IMEM 。
CPU内有运算器和控制器,控制器的功能在于控制运算器和其他模块(乘法器除法器中断处理器等),传入正确数据。(本例将CPU和Controller写在了一起,实际分开更好)
如何载入指令进行测试?
IMEM模块用于根据pc读取instruction。在其中添加ROM IP核,设置为16进制1024*32,载入要执行的coe文件。
如何获取coe文件? 下载MARS(MIPS汇编程序和运行时模拟器),写入程序导出为16进制文件,再在该16进制文件前添加
memory_initialization_radix = 16;
memory_initialization_vector =
如何调试程序?
首先,先静态纠错。将每条指令过一遍,检查模块的接口及数据位数。
然后再指令memory的IP核中载入待测试的coe文件,进行仿真,将每次指令变化后的pc、instruction、寄存器结果输出,与Mars的结果比对。
如果发现某条指令错误,将相关的变量在testbench中显示调用,在仿真的波形图中就可以看到了。显示调用方式如下: