2021龙芯杯游记

第一次参加龙芯杯,报名的是团队赛,感受到了前排大佬的实力碾压…

一切的开始

这学期有计算机组成原理的课程设计实验,要求实现一个简单的(中断都没有)RISC-VCPU,考虑到课程设计实验的难度不大,我和几个同学很早便完成了实验。

老师看我们的进度快便推荐我们参加龙芯杯比赛。我们早在四月便完成了报名。

开始动手

当时我们正在上操作系统课程实验,老师突然发了一条消息

pic1

虽然说四月报名参加比赛,但我们三个人一直到七月上旬才开始动手😑

我们花了一周的时间讨论并设计我们CPU的微结构,确定为做一个带Cache的顺序双发射、五级流水线的朴素的CPU。接下来我们用两周的时间完成了初赛作品的设计(ddl永远是第一驱动力)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Git commits by month:

month sum
Jan 0 |
Feb 0 |
Mar 0 |
Apr 0 |
May 4 |█
Jun 5 |█
Jul 81 |████████████████████████████████
Aug 112 |████████████████████████████████████████████
Sep 0 |
Oct 0 |
Nov 0 |
Dec 0 |

在初赛提交的晚上,我们临时发现最新的版本有Bug,会导致无法通过系统测试部分功能,并且性能测试有一定的几率出现极低的分数。我们三个人立即开始回滚版本,但是由于没有保存以前综合的bitstream,只能立即综合,与时间赛跑。这时候,学校的后勤不知道在想什么,没有任何预告的把宿舍的电闸拉了….

最后有惊无险的赶在截止前几分钟把作品提交了上去

准备复赛

初赛提交完成后,我们开始看复赛的要求,我们的基本目标是跑起来一个PMON,这样复赛演示起评分能有10分。

首先不得不吐槽一下PMON,这个上古世纪的东西,只能用GCC4编译,我一开始编译了一个mipsel版本的GCC11尝试用于编译PMON,结果报出各种花里胡哨的错误,有一些能够手动修改,但是PMON里面有很多宏定义的东西,涉及类型转换、判断等,这些由于我实力不足,实在没办法修改,只能安装一个GCC4

解决编译工具链的问题后,要考虑阉割功能,首先是Cache指令,这个实现起来相对复杂,我们全局搜索并删除了它们。

接着是TLB相关指令,我们考虑到如果复赛不加点功能好像说不过去,于是参照A13手册实现了简易的TLB功能。TLB是一个大坑,它堵在关键路径上:一条TLB表项就是90位,并且考虑到PageMask这个东西,在确定那些位要保留上是一个十分深的逻辑。我们一开始做了32个表项,没想到连50MHz都上不去了….最后通过拆分TLB功能所在的流水级(我们没有加流水级)并且降低表项到4,勉强保证了75MHz的频率(初赛时有88MHz

接下来是十分无语的问题,我们使用自己编译定制的PMON,在上电后解压内核时发生了CRC校验错误😓,此时距离复赛提交的时间不多了,我们怀疑是gzip版本过于先进,导致PMON自带的解压代码无法识别(未验证)。我们只好使用IDA,对着龙芯提供的PMON二进制进行逆向修改。

我们在跑通PMON后想着能否更近一步,跑一个uCore,接着发现uCore需要使用到32TLB表项,并且需要TLBWR指令支持(我们只实现了三个基本的TLB指令)。我把uCore的源代码进行了魔改,用TLBRTLBWI模拟了TLBWR指令。但是上电后发现uCore在卡在等待中断上了,一时间找不到问题的源头,只好放弃了uCore。此时距离复赛提交只有两天了。

我们马上讨论,准备演示程序自己复刻一个Ping PongPong - Wikipedia)。我们使用到了两块FPGA,一块是龙芯实验箱,另一块是计组实验用的Nexys4DDRN4DDR上运行了我计组实现写的带串口的简易RISC-VCPU,当作手柄和实验箱通信。实验箱上运行着团队大佬手写的汇编Pong,他用汇编实现了一个线程调度,中断注册等功能的简易操作系统内核,然后在内核上实现了Pong的主程序。

Pong

现场加指令

这一部分听学长讲一般都是很简单的指令,比如说max或者min之类的,没想到我们这一次要求加一个filter指令:记录所有filter的数据,去除两个最大值、两个最小值,返回剩下的和,难度比往年有所增加。

这个也不是很难,只要维护最大值、最小值以及和总和即可。

答辩

答辩还算顺利。答辩前,我们猜想了几个问题:“为什么没有跑uCore”,没想到还真被问到了 …

评委只问了三个问题:“为什么没有跑uCore”、“游戏怎么写的”、“怎么逆向的代码”,感觉和CPU完全不擦边,估计是我们的作品没什么亮点

对我们而言,就是奔着三等奖去的(过了初赛的保底三等),毕竟我们投入的时间太少,前前后后只有一个月。

总结

这个比赛越来越难打了

pic2
  1. 要想进复赛一定得有一个Cache
  2. 得保证充足的时间,理想的情况是在初赛时就要把复赛准备做的东西完成
  3. 要想拿名次,操作系统至少跑一个uCore,最好是Linux,这个基本上来说是二三等奖的分水岭

=== Update(2021.8.25) ===

今天正好有空,继续完善了一下之前的项目,跑通了uCore

  1. 修复时钟中断产生时没有将IP[7]1的问题
  2. 添加TLBWR指令:如果不做的话可以手动模拟TLBWR过程
  3. 增加特权级(uCore代码里面使用了KSU,但可以偷懒不做Supervisor,只做UM即可):这个一定要实现,在处理TLB REFILL时会根据特权级进行不同的操作。最简单的“取巧做法”就是单让UM位可写,其它不管
uCore

=== Update(2021.9.10) ===

顺手移植了一下RT-Thread操作系统(My Fork

这里主要修改了以下几个地方:

  1. 基于ls1bls1c的代码进行精简,创建新的NSCSCC板级支持包
  2. 删除EHB指令(一个侵入式的修改,将MIPS通用启动过程中的EHB指令替换成NOP
  3. 自定义编译工具链(GCC11 + Newlib,编译时不产生Branch Likely指令)

目前遗憾的是没能驱动网卡 :cry: