用 verilog 实现的支持 MIPS32r2el 指令集的一个子集的五级流水线 CPU,同时 SoC 包含 SRAM 内存控制器和串口控制器。可以直接用 Vivado 2019.2 打开。
实现指令包括 supervisor-32 要求的 21 条指令以及 MUL
和 SLTU
(用于适配决赛现场汇编程序任务,实现无符号整数比较大小)。
实验板上提供了 4 片型号为 IS61WV102416-10 (1Mx16bit) 的异步 SRAM,每两片组成一个 4MB 的存储,总存储空间大小为 8MB,每组存储提供了 20 位的地址线和 32 位数据线。总线模块按照监控程序的要求,将它们分别映射到 0x80000000 和 0x80400000 开始的地址空间。
实验板上提供了串口 rx 和 tx,总线模块利用提供的串口收发模块 async.v 将串口数据映射到 0xBFD003F8 ,将串口状态映射到 0xBFD003FC (详细定义可见监控程序的要求)。
FPGA 芯片型号为 Xilinx Artix(R)-7 xc7a200tfbg676-2 。实验板上晶振频率为 50MHz 和 11.0592MHz,设计只用到了前者。实验板上提供了 vga 接口、16 个 led 灯和两个 7 段数码管,在顶层文件中实现了一些电路驱动 7 段数码管实现 0 到 99 的计时,驱动 led 实现流水灯,驱动 vga 显示一个静态图像。这些与 cpu 无关,但是可以测试板子是否正常工作。具体管脚定义可参见约束文件。
CPU 可以正常通过一级评测、二级评测和三级评测。将位流下载到 FPGA 上,将监控程序写入 0x80000000,启动 term 并连接到串口,复位芯片,CPU 将从 0x80000000 开始取指执行。监控程序将会向串口输出信息,此时可以使用 term 与 CPU 交互。
因为懒,未实现 cache 。使用了 mmcm 分频模块,将主频提高到 60MHz。参考了雷思磊的《自己动手写CPU》采用经典五级流水,使用数据前递解决相关问题,在无法解决相关问题时和指令数据访存冲突时暂停流水线。
在龙芯系统能力培养远程试验平台上测试结果如下:
Test | Time |
---|---|
STREAM | 0.105s |
MATRIX | 0.164s |
CRYTPONIGHT | 0.419s |
和 | 0.688s |
求算术平方根。给你一个 32 位非负整数,求算术平方根(向下取整),测试数据位于 0x80400000 ~ 0x80500000,共 0x40000 个,将结果写入到 0x80500000 ~ 0x80600000。
思路:使用二分法。
先花 10 秒写出一个等价的 C 语言程序:
unsigned getSqrt(unsigned fuck)
{
unsigned l = 0, r = fuck;
while (l < r)
{
unsigned mid = (l+r+1) / 2;
if (mid*mid <= fuck) l = mid;
else r = mid-1;
}
return l;
}
缺点:(1) 会溢出 (2) 会很慢
优化点:
- 将合法区间改为 [l, r),这样mid不用写 +1(初始r=fuck+1);
- 直接计算sum=l+r,判断条件改为 sum*sum/4<=fuck ;
- 将初始右端点改为当 fuck>=65536 时钦定为 65536,减小初始解空间;
- 压榨延迟槽。
最终运行时间: 0.719s
上传到 github 的代码删除了十分难看的设计报告,改为本 README 文档,并修复了 UTF-8 和 GB2312 之间编码转换的错误,将文件编码统一为 UTF-8。