Skip to content

PA-1实验报告

211275022田昊东

PA1-1

目标

  • 实现内存的模拟
  • 实现寄存器的模拟

ppt后题目

  • struct
  • 是一种自定义数据类型,由若干成员组成
  • 可以用于存储一组数据类不同或相同的变量
  • 不同数据成员之间相互独立,存储在一段连续的内存空间的不同位置
  • union
  • 一个union内可以包含多个不同的成员变量,不同成员变量共享同一块内存。
  • union占用空间的大小等于成员变量中占用空间最大的成员的大小。

  • union与struct的区别:

  • struct中的成员是按顺序依次排列,互相独立,其内存是其成员占用内存的加和(由于内存对齐机制可能会更大)。而union中的成员共用同一块内存,union类型占用的内存就是其成员中占用内存的最大值,union中的成员是对同一地址的的不同表现方式。

  • 改变union中一个成员的值可能会改变其他成员的值,而struct中不同成员之间是相互独立的

  • 寄存器结构体的参考实现为什么把部分struct改成了union

  • image-20230316144702242

  • 如图所示,除了直接访问%eax(全部的32位),还要能够访问%ax(前16位)、%al以及%ah。通过第一层union实现这一点:uint32_t、uint64_t、和uint8_t[2]共用一块内存,实现分区访问
  • 第二层union使得第一层union和一个uint32_t的变量val公用bb一块内存,提供通过val直接访问一整行的数据
  • 第三层union将细分的结构(第二层union)的数组与八个带有寄存器名称的uint32_t变量组合再一起,使得可以通过名称来访问对应的区域。

小结

  • 这一部分需要实际操作的内容很少,但需要理解union的含义,在pa很多代码中都使用了union这种数据结构(比如 CPU_STATE以及FLOAT),这种数据结构实现了对统一数据的不同访问方式。在不占用额外空间的前提下,极大的方便了数据的访问。
  • 在 CPU_STATE,可以根据具体寄存器不同,实现对寄存器一行内不同片段的访问(比如访问EAX前8位AL,前16位AX)
  • 在FLOAT中既可以通过fval直接获取浮点数的真值,也可以分别获取浮点数的符号位、阶码、尾数。

PA1-2

目标

  • 了解无符号整数和带符号整数的机器级表示
  • 实现NEMU对ALU的模拟

问题和解决

  • 首先为了简化代码自定义了一些函数

  • mysign用于提取符号位

  • c uint32_t mysign(uint32_t x, size_t data_size) { return (x>>(data_size-1))&1; }

  • set0用于将多余的高位置零

  • c uint32_t set0(uint32_t x, size_t data_size) { return x & (0xFFFFFFFF>>(32-data_size)); }

  • getcom获取相反数的补码(包括符号位在内各位取反末尾加一)

  • c uint32_t getcom(uint32_t x, size_t data_size)//求-x补码 { x=~x; return set0(x+1,data_size); }

  • alu_add

  • alu_add的实现不难,主要是要注意对标志位的处理(比较容易出错的是CF和OF)

    • CF进位:针对无符号数,通过result<src判断
    • OF溢出:针对有符号数,如果两个同号数相加结果为异号则显然说明发生了溢出
  • alu_adc

  • 相当于进行了两次加法,主要需要注意对两次加法得到的标志位的处理

    • 两次中至少发生了一次进位就将CF置1
    • 两次中发生了恰好一次溢出就将OF置1(溢出两次相当于运算数和结果同好,即没有发生溢出)
  • alu_sub

  • 通过getcom把src的补码转化为-src的补码,再转化为加法进行计算

  • alu_mul

  • 如果高位不全是0,则将CF和OF都置一

  • alu_sar

  • 注意要先提取出符号位,右移过程中高位要补符号位

  • alu_idiv

  • 这个修改了比较久实现的比较复杂:提取sec和dest的符号位,如果是负数则用getcom转化为正数的补码,然后直接相除,最后得到的也是正数。根据两个操作数的正负情况决定是否进行一次getcom翻转为负数。

小结

  • 本部分的实现有一定的难度,需要对编码类型、数据计算原理,操作指令含义,标志位含义有充分的理解,稍有偏差就会产生错误。

PA1-3

目标

  • 实现浮点数规格化
  • 实现浮点数加减乘除运算

问题和解决

  • 规格化浮点数
  • 实验指南中多次提到:”为了配合非规格化数的阶码为0表示2-126需要额外将尾数右移一次“。这段化我开始没有完全理解,时间上也有错误,经过调试才明白真正的含义:尾数左移一位x相当于乘以2,exp相应减一相当于浮点数大小保持恒定。而exp从1到0时浮点数的阶数都是2-126没有发生变化,也就相当于浮点数的值变为原来的二倍,因此要再额外右移一次进行修正
  • 其他的部分就按照框架的思路写就能完成。就是要足以一些边界值的处理,尤其是exp=0,exp=255等情况,需要讨论分别处理。

ppt后题目

  • 为浮点数加法和乘法各找两个例子:1)对应输入是规格化或非规格化数,而输出产生了阶码上溢结果为正(负)无穷的情况;2)对应输入是规格化或非规格化数,而输出产生了阶码下溢结果为正(负)零的情况。是否都能找到?若找不到,说出理由。
  • 加法:
    • 1:0:11111110:1(*23)+0:11111110:1(*23)
    • 由于会产生进位,因此规格化后会变为inf
    • 2:0:11111110:1(*23)+1:11111110:1(*23)乘法:
    • 规格化后阶码为0会产生下溢,结果为0
  • 乘法:
    • 1:0:11111110:1(*23)*0:11111110:1(*23)
    • 由于乘法阶码相加,自然会造成阶码上溢,结果为inf
    • 2:0:00000001:0(*23)*0:00000001:0(*23)
    • 阶码相加之后小于最低值,发生阶码下溢,结果为0

小结

  • 这一部分需要完成的代码不算多,但我认为是整个pa1中最难的部分,浮点数的表示规则相对复杂,有些概念不是很好理解。而且这部分的细节很多,遗漏任何一步都无法正确完成,并且由于需要自己写规格化函数,在确认出错位置、调试上有一定的难度,只能通过打印大量数据,再进行分析。

总结

  • 经过这一阶段的实践,对理论课上所学的对应内容有了更深的理解。只有真正上手操作,才能理解许多规则及方法的制定原因。nemu框架代码有降低了体验这个过程的门槛,能很有效的帮助学习和理解。