前言
到INF以后开始改行做FPGA驱动和异构计算API的开发,相比于之前的网络库的工作又更加底层。虽然我们现在的PCI驱动已经相对成熟,要填坑的地方已然不多,但很多细节还是有必要理解透彻,以便未来继续踩坑……于是最近花了好几个周末的时间来复习IA32系统结构,彻底啃完了CSAPP(早该看完了,拖延症啊拖延症),然后又刷通了NJU的系统结构实验ics2016,总体感觉收获还是不小的。主要在于系统结构里太多的概念如果只是看了理论,很容易就忘掉了,毕竟这些东西跟日常工作关系不大,导致看书跟亲自动手编码所获得的经验和理解程度完全不一样。
NEMU
这个系统结构实验主要的内容其实就是实现了一个简易或者说简陋版本的IA32虚拟机,虽然代码量不是特别大,性能也比较捉襟见肘,但麻雀虽小五脏俱全,写完之后能够跑起来简易版的操作系统——实际上只能提供最基础的系统调用,亮点在于在此基础上能运行起来简单的打字小游戏,甚至是DOS版仙剑奇侠传!这个效果就比较有意思了,但从整个工程的实现细节上面,看得出来为了实现这样的有趣结果,设计实验的同学想必踩了不知道多少个坑。

总而言之,虽然模拟指令集听起来很容易,但在实验第二阶段亲自动手撸一遍大量CISC指令的模拟,会让人感觉简直像是吃了翔。i386这过于杂乱的指令码设计,繁杂的操作数格式以及语焉不详甚至各种出错的文档,让人深深感到对这个世界产生了质疑:这种恶心人的东西是如何在市场占据支配级地位的?!我只能理解为当初的编译器和链接器作者把这些繁杂的细节封装得足够好,所以消费者感受不到罢了。
另外nemu这个模拟器比较令人头疼的一点是它对IA32内存机制的模拟性能实在是惨剧。写完之后跑仙剑奇侠传的时候发现游戏卡的惊人,profile一下之后发现大量时间都花在内存读写上面——也难怪,分段、TLB、分页、L1/L2 cache这些操作级联起来,一次访存慢上几百倍毫不夸张,毕竟用循环去模拟组相联甚至是全相联的高速缓存,本身就是一件性能低的惨绝人寰的事情……硬件电路可以高效完成缓存查询,但是软件不行啊!而且即便关掉cache模拟,性能也有可能不升反降,因为一层层的模拟内存调用开销实在太大,在现有的这个设计框架下简直没法优化。因为这东西跟真正的虚拟机相比还是有所区别,虚拟机可以通过一些取巧的方式“欺骗”硬件来让它高效地完成地址翻译的操作。所以NEMU这个“伪虚拟机”运行一些简单程序来追踪cache命中率之类这样的profile用途还算能胜任,复杂度超过仙剑的程序,就没法在上面折腾了。
Kernel
上文已经提到过,这个Kernel实际上是一个相当简化的版本。这玩意的难度主要在于调试,因为直到实验的最后阶段才加入中断以及串口输出的支持,所以在此之前,调试任何nemu内运行的代码都只能靠读汇编和动态跟踪汇编。不过这个过程倒是大大加深了我对gcc编译器的理解,其实是一种不错的体验。其实总体而言,这个实验中最珍贵的地方就在于踩坑+调试了,非常非常涨经验。
SDLPAL
最后说两句这个仙剑奇侠传。整个实验最大的亮点就是它,制作实验的同学把它移植过来想必是花了很大心血的。实际上我们看到SDL库最终用到的也就寥寥几个函数而已,虽然在我的MBP上面跑起来卡顿的不行,但真的是从上到下把所有东西都打通了。不过必须吐槽,这个实验放在公网上面,那么理应也把数据都准备好啊,结果我东拼西凑找了好久才把相应的数据文件找齐,也是醉了。
另外,其实有一个不太完善的一点是在kernel里面硬编码了这些数据文件的名称、size等等,实际上这里完全可以再复杂一点,设计一种支持创建、读写文件的fs,把文件名信息写到虚拟磁盘上而不是硬编码到代码里面,这样整体组织上面就漂亮多了。
End
嗯,十一期间撸完了cs143,现在又搞定了ics2016,于是下一个目标就是MIT 6.828了,希望能够在两个月以内完成。回想起来,本科的大好时光都拿去玩ACM和研究海洋数值模型了,转行之后悔之晚矣,只能靠业余时间多撸代码吧,这些优秀的作业结合经典著作,真的是给人带来对相应领域本质上的理解。