本系列所有博客,知识讲解、习题以及答案均由北航计算机学院计算机组成原理课程组创作,解析部分由笔者创作,如有侵权联系删除。
从本节开始,课程组给出的教程中增添了很多视频讲解。为了避免侵权,本系列博客将不会搬运课程组的视频讲解,而对于文字讲解也会相应地加以调整,重点在于根据笔者自己的理解给出习题的解析。因此带来的讲解不到位敬请见谅。
(本章请即将开始搭建 CPU 时再进行阅读)
首先,要明确 CPU 支持哪些指令,我们的测试程序中使用到的指令不能超出 CPU 支持的范围。
对于测试程序而言,我们追求的并不是过程与结果有多么巧妙,我们的目的只有一个,那就是全面的测试每条指令。比如测试加法,我们就要把正正相加,负负相加,正负相加的情况都考虑到。
在用 Mars 编写测试程序时,对于一些伪指或看起来合法(但其实不合法,比如立即数溢出)的指令,MARS 会自动将其拆解转换成若干条基本指令,这样就违背了设计的初衷,如下图。所以将代码导入到 CPU 中测试之前,一定要注意下这个问题。
假设我们已经设计好了一个 CPU 程序,它支持 ori
, lui
, add
, lw
, sw
, beq
这些指令,现在我们要写个测试程序来测试我们 CPU 程序的正确性(暂不考虑延迟槽)。
首先我们必须要知道,测试程序的第一步一定是测试最基本的指令,只有基本指令正确了,我们才可以测试更复杂的指令。这些最基本的指令一般都是在测试时能够不依赖其他类型的指令就能判断指令正确性的指令,比如 ori
、lui
、addi
等。
比如这里,我们要先测 ori
和 lui
指令,因为其他指令都得靠这两条指令为寄存器赋值,然后才能测试,不然寄存器的值都是 0,无法进行测试。
第一条我们先测最基本的,与 0 进行 or 运算,然后第二条再测试两个非 0 数直接的 or 运算。从指令集的解释中,我们知道,ori
指令的第三个立即数参数是无符号扩展,所以就不存在负数的情况。
根据指令集对 lui
的介绍,其实我们只有测第一条指令就行了,后面两条指令是为了使用 ori
和 lui
这两条指令构造一个负数,用于后面 add
指令的测试。
对于 add
指令,我们利用之前 ori
和 lui
准备好的寄存器进行这三种情况的测试。
对于 sw
和 lw
指令,我们得先测 sw
往内存中存数据,这样才能通过 lw
取数据,不然内存中数据都是 0,lw
指令对不对我们也看不出来。
这里我用了这么多 sw
指令,主要是为了把之前的数据先保存下来,释放寄存器。
这里我们正好用之前 sw
存入内存的数据进行测试,最后再将结果存入内存,释放寄存器。
这里把判断成立与不成立的情况都考虑了一遍,最终我们只要看内存中的数据就可以判断 beq
指令有没有正确的跳转。
在我们的程序中,已经把所有有用的数据都存入到了内存中。所以只要将汇编程序对应的二进制码导入到 CPU 中,运行之后查看其内存中的数据,和 Mars 运行结果一比较,我们就可以看出程序有没有错。
本讲将会介绍如何在 logsim 搭建的 CPU 电路和使用 Verilog 语言编写的 CPU 工程文件中使用测试程序验证 CPU 的正确性。
v2.0 raw
2.导入到 IFU 模块中的 ROM 中
(1) 选中 ROM 元件,右键 -> Edit Contents
(2) 在弹出的编辑框中点击 Open 导入我们准备好的测试程序。
3.运行 CPU 电路
4.检查结果
1.准备测试程序
2.导入到 IM 中
reg [31:0] im[1023:0]
就是一个可以存储 1024 条指令的 reg 数组,每个数组元素是 32 位,也就是一条指令的大小,数组下标是 0~1023。(1) 格式:$readmemh(“file”, mem_name, start_addr, stop_addr)
(2) file 是导入的 16 进制测试文件,不使用绝对路径时要将其放在工程文件下。
(3) mem_name 是我们存储元件的名字,这里就是数组的名字 im。
(4) start_addr 和 stop_addr 是测试文件导入到存储元件中的起始地址和终止地址,在这里就是数组的下标,是可选参数。
$readmemh("code.txt", im);
(1) code.txt 是测试文件,im 是 reg 数组名。
(2)因为 im 数组大小为 4KB,所以提取指令时只需要用到 32 位地址中的前 12 位。相对于我们设置的起始地址 0x0000_3000 而言,前 12 位都是 0,所以指令正好是从数组的首个元素开始存储。因此,这里就不用地址参数了。
3.运行 CPU 程序
4.检查结果
在编写测试程序时,利用有限的指令去构造指定的数据也是很重要的。
比如我们只能使用ori和lui指令(必须是标准指令),如何去构造一个负数呢?
从下列选项中选择能够使$a0值为-1的选项?
A. ori $a0,$0,0xffffffff
B. ori $a0,$0,0xffff
lui $a0,0xffff
C. lui $a0,0xffff
ori $a0,$a0,0xffff
D. lui $a0,-1
答案:C
在我们的CPU设计中,所有的寄存器不用经预处理就可以与mars的行为保持一致?
A. 对
B. 错
答案:B
假如我们的CPU只支持 ori 指令,我们先会使用Mars编写测试程序,并将其导出到CPU上运行。下面会给出在Mars上编写的测试指令,试问,哪条指令能够在CPU上正确的运行呢?
A. ori $a0,$0,-1
B. ori $a0,$0,60000
C. ori $a0,$0,70000
D. or $a0,$0,$0
答案:B