功能测试程序集为 MIPS 汇编程序,用于测试 CPU 功能并在实验箱上显示。当CPU从内存中执行测试程序后,实验箱上的数码管和 LED 灯显示分数和测试通过情况。文档介绍了功能测试的使用方法和功能测试程序和环境。
本小节介绍功能测试程序包含的内容,可以结合测试程序阅读。
功能测试的主程序位于 src/start.S,src/inst 目录下为测试 文件 n1_add.S
~ n93_tlbwr.S
,每个测试文件对应一个功能测试点。功能测试程序集包含的功能测试点如下:
序号 | Hex | 测试程序 | 功能测试点 |
---|---|---|---|
1 | 0x01 | ADD | 执行 ADD 指令是否产生正确的运算结果(未测试整型溢出例外的情况) |
2 | 0x02 | ADDI | 执行 ADDI 指令是否产生正确的运算结果(未测试整型溢出例外的情况) |
3 | 0x03 | ADDU | 执行 ADDU 指令是否产生正确的运算结果 |
4 | 0x04 | ADDIU | 执行 ADDIU 指令是否产生正确的运算结果 |
5 | 0x05 | SUB | 执行 SUB 指令是否产生正确的运算结果(未测试整型溢出例外的情况) |
6 | 0x06 | SUBU | 执行 SUBU 指令是否产生正确的运算结果 |
7 | 0x07 | SLT | 执行 SLT 指令是否产生正确的运算结果 |
8 | 0x08 | SLTI | 执行 SLTI 指令是否产生正确的运算结果 |
9 | 0x09 | SLTU | 执行 SLTU 指令是否产生正确的运算结果 |
10 | 0x0a | SLTIU | 执行 SLTIU 指令是否产生正确的运算结果 |
11 | 0x0b | DIV | 执行 DIV 指令是否产生正确的运算结果 |
12 | 0x0c | DIVU | 执行 DIVU 指令是否产生正确的运算结果 |
13 | 0x0d | MULT | 执行 MULT 指令是否产生正确的运算结果 |
14 | 0x0e | MULTU | 执行 MULTU 指令是否产生正确的运算结果 |
15 | 0x0f | AND | 执行 AND 指令是否产生正确的运算结果 |
16 | 0x10 | ANDI | 执行 ANDI 指令是否产生正确的运算结果 |
17 | 0x11 | LUI | 执行 LUI 指令是否产生正确的运算结果 |
18 | 0x12 | NOR | 执行 NOR 指令是否产生正确的运算结果 |
19 | 0x13 | OR | 执行 OR 指令是否产生正确的运算结果 |
20 | 0x14 | ORI | 执行 ORI 指令是否产生正确的运算结果 |
21 | 0x15 | XOR | 执行 XOR 指令是否产生正确的运算结果 |
22 | 0x16 | XORI | 执行 XORI 指令是否产生正确的运算结果 |
23 | 0x17 | SLLV | 执行 SLLV 指令是否产生正确的移位结果 |
24 | 0x18 | SLL | 执行 SLL 指令是否产生正确的移位结果 |
25 | 0x19 | SRAV | 执行 SRAV 指令是否产生正确的移位结果 |
26 | 0x1a | SRA | 执行 SRA 指令是否产生正确的移位结果 |
27 | 0x1b | SRLV | 执行 SRLV 指令是否产生正确的移位结果 |
28 | 0x1c | SRL | 执行 SRL 指令是否产生正确的移位结果 |
29 | 0x1d | BEQ | 执行 BEQ 指令是否产生正确的判断和跳转结果(延迟槽指令为nop,未测试延迟槽) |
30 | 0x1e | BNE | 执行 BNE 指令是否产生正确的判断和跳转结果(延迟槽指令为nop,未测试延迟槽) |
31 | 0x1f | BGEZ | 执行 BGEZ 指令是否产生正确的判断和跳转结果(延迟槽指令为 nop,未测试延迟槽) |
32 | 0x20 | BGTZ | 执行 BGTZ 指令是否产生正确的判断和跳转结果(延迟槽指令为 nop,未测试延迟槽) |
33 | 0x21 | BLEZ | 执行 BLEZ 指令是否产生正确的判断和跳转结果(延迟槽指令为 nop,未测试延迟槽) |
34 | 0x22 | BLTZ | 执行 BLTZ 指令是否产生正确的判断和跳转结果(延迟槽指令为 nop,未测试延迟槽) |
35 | 0x23 | BGEZAL | 执行 BGEZAL 指令是否产生正确的判断、跳转和链接结果(延迟槽指令为 nop,未测试延迟槽) |
36 | 0x24 | BLTZAL | 执行 BLTZAL 指令是否产生正确的判断、跳转和链接结果(延迟槽指令为 nop,未测试延迟槽) |
37 | 0x25 | J | 执行 J 指令是否产生正确的跳转结果(延迟槽指令为 nop,未测试延迟槽) |
38 | 0x26 | JAL | 执行 JAL 指令是否产生正确的跳转和链接结果(延迟槽指令为nop,未测试延迟槽) |
39 | 0x27 | JR | 执行 JR 指令是否产生正确的跳转结果(延迟槽指令为 nop,未测试延迟槽) |
40 | 0x28 | JALR | 执行 JALR 指令是否产生正确的跳转和链接结果(延迟槽指令为 nop,未测试延迟槽) |
41 | 0x29 | MFHI | 执行 MTHI 指令是否正确地将寄存器值写入 HI 寄存器,执行MFHI 指令是否正确地读出 HI 寄存器的值到寄存器 |
42 | 0x2a | MFLO | 执行 MTLO 指令是否正确地将寄存器值写入 LO 寄存器,执行MFLO 指令是否正确地读出 LO 寄存器的值到寄存器 |
43 | 0x2b | MTHI | 执行 MTHI 指令是否正确地将寄存器值写入 HI 寄存器,执行MFHI 指令是否正确地读出 HI 寄存器的值到寄存器 |
44 | 0x2c | MTLO | 执行 MTLO 指令是否正确地将寄存器值写入 HI 寄存器,执行MFLO 指令是否正确地读出 HI 寄存器的值到寄存器 |
45 | 0x2d | BREAK | 执行 BREAK 指令是否正确地产生断点例外 |
46 | 0x2e | SYSCALL | 执行 SYSCALL 指令是否正确地产生系统调用例外 |
47 | 0x2f | LB | 结合 SW 指令,执行 LB 指令是否产生正确的访存结果 |
48 | 0x30 | LBU | 结合 SW 指令,执行 LBU 指令是否产生正确的访存结果 |
49 | 0x31 | LH | 结合 SW 指令,执行 LH 指令是否产生正确的访存结果 |
50 | 0x32 | LHU | 结合 SW 指令,执行 LHU 指令是否产生正确的访存结果 |
51 | 0x33 | LW | 结合 SW 指令,执行 LW 指令是否产生正确的访存结果 |
52 | 0x34 | SB | 结合 LW 指令,执行 SB 指令是否产生正确的访存结果 |
53 | 0x35 | SH | 结合 LW 指令,执行 SH 指令是否产生正确的访存结果 |
54 | 0x36 | SW | 结合 LW 指令,执行 SW 指令是否产生正确的访存结果 |
55 | 0x37 | ERET | 执行 ERET 指令是否正确地从中断、例外处理程序返回 |
56 | 0x38 | MFC0 | 执行 MTC0 指令是否正确地将寄存器值写入目的 CP0 寄存器,执行 MFC0 指令是否正确地读出源 CP0 寄存器的值到寄存器 |
57 | 0x39 | MTC0 | 执行 MTC0 指令是否正确地将寄存器值写入目的 CP0 寄存器,执行 MFC0 指令是否正确地读出源 CP0 寄存器的值到寄存器 |
58 | 0x3a | ADD_EX | 测试 ADD 指令整型溢出例外 |
59 | 0x3b | ADDI_EX | 测试 ADDI 指令整型溢出例外 |
60 | 0x3c | SUB_EX | 测试 SUB 指令整型溢出例外 |
61 | 0x3d | LH_EX | 测试 LH 指令访存地址非对齐例外 |
62 | 0x3e | LHU_EX | 测试 LHU 指令访存地址非对齐例外 |
63 | 0x3f | LW_EX | 测试 LW 指令访存地址非对齐例外 |
64 | 0x40 | SH_EX | 测试 SH 指令访存地址非对齐例外 |
65 | 0x41 | SW_EX | 测试 SW 指令访存地址非对齐例外 |
66 | 0x42 | ERET_EX | 测试取指地址非对齐例外 |
67 | 0x43 | RESERVED_INSTRUCTION_EX | 测试保留指令例外 |
68 | 0x44 | BEQ_DS | 测试延迟槽 |
69 | 0x45 | BNE_DS | 测试延迟槽 |
70 | 0x46 | BGEZ_DS | 测试延迟槽 |
71 | 0x47 | BGTZ_DS | 测试延迟槽 |
72 | 0x48 | BLEZ_DS | 测试延迟槽 |
73 | 0x49 | BLTZ_DS | 测试延迟槽 |
74 | 0x4a | BGEZAL_DS | 测试延迟槽 |
75 | 0x4b | BLTZAL_DS | 测试延迟槽 |
76 | 0x4c | J_DS | 测试延迟槽 |
77 | 0x4d | JAL_DS | 测试延迟槽 |
78 | 0x4e | JR_DS | 测试延迟槽 |
79 | 0x4f | JALR_DS | 测试延迟槽 |
80 | 0x50 | BEQ_EX_DS | 测试延迟槽例外 |
81 | 0x51 | BNE_EX_DS | 测试延迟槽例外 |
82 | 0x52 | BGEZ_EX_DS | 测试延迟槽例外 |
83 | 0x53 | BGTZ_EX_DS | 测试延迟槽例外 |
84 | 0x54 | BLEZ_EX_DS | 测试延迟槽例外 |
85 | 0x55 | BLTZ_EX_DS | 测试延迟槽例外 |
86 | 0x56 | BGEZAL_EX_DS | 测试延迟槽例外 |
87 | 0x57 | BLTZAL_EX_DS | 测试延迟槽例外 |
88 | 0x58 | J_EX_DS | 测试延迟槽例外 |
89 | 0x59 | JAL_EX_DS | 测试延迟槽例外 |
90 | 0x5a | JR_EX_DS | 测试延迟槽例外 |
91 | 0x5b | JALR_EX_DS | 测试延迟槽例外 |
92 | 0x5c | TLBWI | 测试TLBWI指令 |
93 | 0x5d | TLBWR | 测试TLBWR指令 |
功能测试大部分为随机测试,随机数预先生成并写入程序中。
功能测试采用宏指令,定义宏指令的头文件位于 src/include 下,分为 6 个文件:
- inst_def.h 定义了第 1~54 功能测试点的指令宏定义;(第 55~57 功能测试点不采用宏定义)
- inst_test.h 定义了第 1~54 功能测试点的测试指令宏定义;(第 55~57 功能测试点不采用宏定义)
- inst_ex_def.h 定义了第 58~67 功能测试点的指令宏定义;
- inst_ex_test.h 定义了第 58~67 功能测试点的测试指令宏定义;
- inst_delay_slot_def.h 定义了第 68~91 功能测试点的指令宏定义;
- inst_delay_slot_test.h 定义了第 68~91 功能测试点的测试指令宏定义。
例如第 1 个功能测试点 ADD,在功能测试主程序 start.S 中 jal 指令调用 n1_add_test:
src/start.S
+++++++++++
…
inst_test:
jal n1_add_test #add
nop
…
n1_add_test 功能测试子程序如下:
src/inst/n1_add.S
+++++++++++++++++
9 LEAF(n1_add_test)
10 lui a0, 0x100
11 li v0, 0x0
12 ###test inst
13 TEST_ADD(0x0480ff04, 0x40933204, 0x45143108)
14 TEST_ADD(0x2a19dd40, 0xa87971e0, 0xd2934f20)
…
211 TEST_ADD(0x25e5fad8, 0x00000000, 0x25e5fad8)
212 TEST_ADD(0x00000000, 0xdcaf5e62, 0xdcaf5e62)
…
262 TEST_ADD(0x00000000, 0x00000000, 0x00000000)
263 ###detect exception
264 bne v0, zero, inst_error
265 nop
266 ###score ++
267 addiu s3, s3, 1
268 ###output a0|s3
269 inst_error:
270 or t0, a0, s3
271 sw t0, 0(s1)
272 jr ra
273 nop
274 END(n1_add_test)
其中,第 10 行 a0 寄存器存储了测试功能点编号值,这里为 0x1;第 11 行 v0 寄存器存储的是例外检
测,初始值为 0,如果程序出现例外会置为 0xffff0000,在 264 行检测如果出现例外就会跳转到
inst_error;第 12 行到第 262 行为测试指令,TEST_ADD(加数 1,加数 2,正确结果),分别测试了加数 1 和
2 都是随机数、加数 1 或 2 是 0、加数 1 和 2 都是 0 的情况;第 263265 行判断测试过程中是否出现例外,
正确情况下没有例外;第 266267 行,s3 寄存器存测试分值,测试通过一个功能点加 1 分;第 268~273 行
为测试结束,将测试编号和测试分值输出显示并返回主程序。
宏定义 TEST_ADD 位于 inst_test.h 中:
src/include/inst_test.h
+++++++++++++++++++++++
4 /* 1
5 * TEST_ADD(vs, vt, vd)
6 */
7 #define TEST_ADD(vs, vt, vd) \
8 ADD(vs, vt); \
9 li s2, vd; \
10 bne s0, s2, inst_error; \
11 nop
TEST_ADD 将加数 1 和加数 2 传给 ADD(vs, vt),并判断目的寄存器 s0 的值是否与正确结果 s2 寄存器的值一致。ADD 宏定义位于 inst_def.h:
src/include/inst_def.h
++++++++++++++++++++++
3 /* 1
4 * ADD(v0, v1)
5 */
6 #define ADD(v0, v1) \
7 li t0, v0; \
8 li t1, v1; \
9 add s0, t0, t1
ADD 将加数 1 装载于寄存器 t0,加数 2 装载于寄存器 t1,结果位于寄存器 s0。
功能测试时,测试程序存储在内存中。具体存放在物理地址段 0x00000000~0x00200000(对应虚拟地址 0x80000000~0x80200000)范围内。程序的入口虚地址为0x80000000。
程序需要控制板上的数码管和LED显示,其控制寄存器的地址由 src/start.S 文件中的LED_ADDR
和NUM_ADDR
宏定义。
本小节介绍功能测试程序编译和链接环境,作为功能测试调试时的选读内容,可以结合代码阅读。
编译和链接环境位于 src/ 目录下,其中: bin.lds 为链接脚本,bin.lds.S 为其源码; convert 将编译生成的二进制可执行文件转换成存储器 RAM 的初始化配置文件,convert.c 为其源码;
Makefile 和 rules.make 规定了编译的配置信息和规则,交叉编译最终生成可执行文件为 main.bin。Makefile 中需要设置交叉编译器命令前缀参数CROSS_COMPILE
,修改该参数可直接修改 Makefile 文件或者在 make 命令行中传入。Makefile 对于硬件运行和仿真运行有分别对应的版本,区别在于硬件运行的版本每条测例后面有等待,以便人观察结果。
默认版本是在硬件运行,编译命令为make
或make ver=test_hw
,清理命令为make clean
或make clean ver=test_hw
仿真版本的编译命令为make ver=sim
,清理命令为make clean ver=sim
。必须加上版本的定义,否则就按照默认版本生成或清除对应的文件。