NEMU PA 1 实验报告
课程地址:
PA1-1 https://www.bilibili.com/video/BV1JE411J7AK
PA1-2 https://www.bilibili.com/video/BV1EE411J7Y6
PA1-3 https://www.bilibili.com/video/BV1fE411H7nS
Guide的仓库及其镜像地址:
GitHub: http://github.com/ics-nju-wl/icspa-public-guide
Gitee: https://gitee.com/wlicsnju/icspa-public-guide实验框架代码及其镜像地址:
GitHub: http://github.com/ics-nju-wl/icspa-public
Gitee: https://gitee.com/wlicsnju/icspa-public
一、实验目的
通过数据的存储开始简单了解NEMU的总体结构,进而从整数和浮点数的表示、存取和运算出发,构建一台完整的计算机。
二、实验步骤
PA1-1 数据的表示和存取
首先我们了解了各种数据(无符号整数,带符号整数,定点/浮点数,非数值型数据)是怎么编码成机器数的;然后进一步了解了cpu是怎么处理数据的:
![](https://img2023.cnblogs.com/blog/2565949/202302/2565949-20230224222508732-1684240432.png)
然后我们进一步了解了NEMU中这些数据的存储的地方以及这些存储地方是怎么被我们写出来的,即NEMU是如何用c语言表示内存和寄存器的:(ISA遵从i386)
![](https://img2023.cnblogs.com/blog/2565949/202302/2565949-20230224222509307-1118513087.png)
通过进一步阅读代码,可以发现内存是由一个uint_8的数组来模拟的,并且给出了从顶层到底层的一系列读写接口(虚拟地址读写、线性地址读写、物理地址读写,需要后面去完成);
了解内存后,我们继续来了解NEMU中的通用寄存器组;
在pa1-1中我们模拟了一个x86体系的通用寄存器组,这个寄存器组拥有八个32位的寄存器;由于寄存器具有兼容性,即如下图,我们通过使用struct类型和union类型来达到模拟效果:
![](https://img2023.cnblogs.com/blog/2565949/202302/2565949-20230224222509655-332413120.png)
typedef struct
{
union
{
union
{
union
{
uint32_t _32;
uint16_t _16;
uint8_t _8[2];
};
uint32_t val;
} gpr[8];
struct
{ // do not change the order of the registers
uint32_t eax, ecx, edx, ebx, esp, ebp, esi, edi;
};
};
…
} CPU_STATE;
PA1-2 整数的表示与运算
在PA1-1中我们了解了NEMU的内存和GPRs组成,在PA1-2中我们将视角放到cpu中,去了解并完成cpu中的运算部件。(需要实现的部分是算术逻辑单元,即ALU)
其中ALU要实现的功能包括各类算术运算(加减乘除)和逻辑运算(与或非)。在这个过程,我们要将需要实现的指令和i386手册比对,通过手册来找到相关指令描述以实现基本操作,同时实现五个符号位(OF CF PF SF ZF)的判断。
实现的指令有:算术运算:ADD ADC SUB SBB MUL IMUL DIV IDIV SHL SHR SAL SAR
逻辑运算:AND OR XOR
对应代码在:
nemu/include/cpu/alu.h
nemu/src/cpu/alu.c
PA1-3 浮点数的表示与运算
在这一章节,我们要在NEMU中模拟浮点数的算术运算单元即FPU;
我们需要实现四个浮点数运算:加减乘除。并同时在它们的实现过程中实现对浮点数结果的规格化处理;相关函数为internal_float_xxx()
。
相关代码:nemu/src/cpu/fpu.c
三、思考题
SUB为什么不能对减数取补码后,简单复用add的CF判断标准?
如果对减数取补码进行运算,如3-6的情况,运算得出的结果补码会为负数,0011 + 1010 = 0 1101,不会发生借位。所以不能简单服用add的cf判断标准。
为浮点数加法和乘法各找两个例子:1)对应输入是规格化或非规格化数,而输出产生了阶码上溢结果为正(负)无穷的情况;2)对应输入是规格化或非规格化数,而输出产生了阶码下溢结果为正(负)零的情况。是否都能找到?若找不到,说出理由。
1)加法:10E38 + 1.0
乘法:3.4E38 * 100.0
2)加法:不能找到,因为对阶运算再进行规格化后,阶码为0时可以表示非规格化浮点数。
乘法:非规格化下溢:( 0 & 0x1 ) * ( 0 & 0x1 )= 0;