基于五阶段流水线的RISC-V CPU模拟器实现

RISC-V是源自Berkeley的开源体系结构和指令集标准。这个模拟器实现的是RISC-V Specification 2.2中所规定RV64I指令集,基于标准的五阶段流水线,并且实现了分支预测模块和虚拟内存模拟。实现一个完整的CPU模拟器可以很好地锻炼系统编程能力,并且加深对体系结构有关知识的理解。在开始实现前,应当阅读并深入理解Computer Systems: A Programmer's Perspective中的第四章,或者Computer Organizaton and Design: Hardware/Software Interface中的有关章节。

本模拟器的代码在GitHub上:https://github.com/hehao98/RISCV-Simulator

一、开发环境 1.1 RISC-V环境的安装与配置

首先,必须搭建RISC-V相关的编译、运行和测试环境。简便起见,本次实验全部基于RISC-V 64I指令集,参考的指令集标准是RISC-V Specification 2.2。为了配置环境,执行了如下步骤。

从GitHub上下载了riscv-tools,从中针对Linux平台配置,编译和安装了riscv-gnu-toolchain。

为了使用官方模拟器作为参照,从GitHub上下载、编译和安装了riscv-qemu。

需要特别注意的是,在编译riscv-gnu-toolchain时,必须指定工具链和C语言标准库所使用的指令集为RV64I,否则在编译的时候编译器会使用RV64C、RV64D等扩展指令集。即使设置编译器编译时只使用RV64I指令集,编译器也会链接进使用扩展指令集的标准库函数。因此,为了获得只使用RV64I标准指令集的ELF程序,必须在riscv-gnu-toolchain中采用如下选项重新编译

mkdir build; cd build ../configure --with-arch=rv64i --prefix=http://www.likecs.com/path/to/riscv64i make -j$(nproc)

在编译时,使用-march=rv64i让编译器针对RV64I标准指令集生成ELF程序。

riscv64-unknown-elf-gcc -march=rv64i test/arithmetic.c test/lib.c -o riscv-elf/arithmetic.riscv 1.2 使用的测试程序和测试方法

对一个体系结构模拟器进行测试有一定难度,主要是由于指令数众多、代码庞大、从而对模拟器代码进行100%覆盖率的测试比较困难。因此,为了便于测试,本模拟器使用了一组由简单到复杂的测试程序,并且实现了单步调试和打印CPU状态的接口。此外,为了便于进行调试和性能分析,还实现了记录执行历史的模块,在程序出错时可以获得完整的指令执行历史和内存快照,便于对出错进行分析。

为了对RISC-V模拟器进行测试,编写了如下程序(见test/文件夹)。比较复杂的是快速排序、矩阵乘法和求Ackermann函数三个。其中,快速排序和矩阵乘法涉及比较多的指令和数据,求解Ackermann函数涉及非常深的递归调用。

lib.c # 自定义的系统调用实现 helloworld.c # 最简单的程序 test_arithmetic.c # 对运算指令的测试 test_branch.c # 对基本分支的测试 test_syscall.c # 对系统调用的测试 quicksort.c # 快速排序 matrixmulti.c # 矩阵乘法 ackermann.c # 求解Ackermann函数

所有程序编译后得到的二进制程序和反编译得到的汇编代码均保存在riscv-elfs/文件夹中。

二、设计概述 2.1 开发环境

我测试的模拟器运行环境为Mac OS X,使用的编程语言为C++ 11,构建环境为CMake,编译器为Apple Clang 10.0.0,编译使用的Flag为-O2 -Wall。开发使用的工具为VS Code。不过,模拟器代码尽量避免了使用标准库以外的平台相关功能,所以应该也能在其他平台和编译器上编译运行。

2.2 设计考量

首先,模拟器的运行必须是健壮的。具体地说,必须能够处理各种非法输入,包括不正常的访存,不正常的ELF文件,非法指令,非法的访存地址等等。编写细致全面的错误处理不仅有助于锻炼系统编程能力,也有助于在早期发现细微的程序错误。

其次,模拟器的实现必须简单、易于理解和易于调试。此模拟器是一个课程项目级别的模拟器,允许的实现时间有限,因此代码实现必须简单,调试系统必须完备,从而尽可能地减少编写程序和调试程序所需要的时间。

此外,模拟器实现的主要目的是能够被用于简单性能评测,因此必须能够尽可能贴近流水线硬件,并可以扩展出分支预测和缓存模拟等各种功能,便于在真正的程序上实验和评测流水线的性能,以及各种分支预测和缓存模拟策略。

本次模拟器的实现并不是要做一个成熟可用的工业级体系结构模拟器,也就是说,本次模拟器的实现并不注重性能和功能的全面性。在性能上,对于极端复杂和庞大的程序,模拟器的程序会执行缓慢,也有可能会消耗过多内存,对于模拟器本身的性能优化不在本实验的范围内。在功能上,为了实现简单,本模拟器使用自定义的系统调用,而不是兼容Linux的系统调用,因此,此模拟器只能运行专门为此编译的RISC-V程序(程序源码参见test/文件夹)。

2.3 编译与运行

编译方法与一个典型的CMake项目一样,在编译之前必须先安装CMake。在Linux或者Mac OS X系统上可以采用如下命令

mkdir build cd build cmake .. make

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zyfxjz.html