南京大学/NJU 人工智能/AI 计算机系统基础/ICS 编程作业/PA 记录
PA2.3
从这里开始记录。
已经能通过大部分测试用例——除了 hello-str 和 string。

观察这两个测试用例究竟是为什么挂了。首先定位到错误的位置,发现都是 putch 函数中发生了内存越界。
但是这两个代码本身并没有这个函数,因此先寻找代码与 putch 函数的关系。不断寻找,最终可以发现这个 putch 是某个 trm.c 中的函数。
根据经验,我们可以判断是 nemu/trm.c,毕竟这是加载在 nemu 上的程序。而想要验证也很简单,只需要在其 putch 函数前加入一条 printf("Hello") 即可,如果 nemu 的报错是识别到了没被植入的指令,就说明是这个 trm.c 了。
而使用 putch 的原因是进入了 panic,因此,只需要把对应的环境函数实现,即可避免进入 panic,从而避免错误。
字符串相关的函数都很好实现,难点在于 sprintf 等。
第一步,参数处理
va_list args;
va_start(args, fmt);
//TODO
va_end(args);
这样可以得到一个 args 的 va_list。
然后每次使用
va_arg(ap, int)
va_arg(ap, char*)
来获取参数列表中的对应类型。
第二部,实现逻辑
按照对应函数逻辑实现即可。
难点,printf
其实实现并不困难,只需要这样实现即可:
int printf(const char *fmt, ...) {
// panic("Not Implemented");
char out[4096];
va_list args;
va_start(args, fmt);
int ret = vsnprintf(out, sizeof(out), fmt, args);
va_end(args);
putstr(out);
return ret;
}
但是问题在于 putstr 这个函数并不能发挥作用!因为这个函数本身就是会访问一个非内存的地址!
实际上,原因在于需要在 make menuconfig 中打开 device 设置,打开之后,就会有一个 mmio(memory map input/output) 的代码被实现,也就是把映射到 nemu 中外设的地址,映射到 nemu 中外设的地址,再有 nemu 中模拟设备的代码,映射到真实的地址。
理论上,把这些东西实现之后,就可以通过了。
在中间的时候,有某个版本突然无法通过 cpu-test 了。本来想用 git bisect 查错,但是对于中间有 git merge 的提交历史,bisect 难以使用。最后没招,只好人眼识别两个版本哪里有差别,结果是因为 addi, xori, ori 的逻辑错了。
这三个指令,本来想着既然立即数只有低 12 位,那我就应该 &0xfff 来截断立即数,结果正确的逻辑就是需要符号扩展到 32 位。

浙公网安备 33010602011771号