Featured image of post 北航CO_P7-MIPS微系统

北航CO_P7-MIPS微系统


MIPS微系统设计方案

概述

刚刚拿到实验教程的时候真的感到无从下手,不过在学长博客和gxpPPT的指引下还是解决了。这里贴出我用到的三个博客以示感谢。

有一说一我觉得助教是刻意把教程弄成这样的。因为教程里都写了P7注重考验同学们的自主设计,并且在设计上给了同学们相当大的自由。不过我觉得还是改了为好。

搭建思路

P7要做的事情有些琐碎,因此选择一个良好的操作顺序非常重要,以下是我的工作流程。

  1. 搭建CP0,建议放M级。
  2. 产生异常,设计出ExcCode信号并随流水线传递到M级,注意课程组给出的条件,注意一条指令多个异常和多条指令同时异常的情况。
  3. 根据CP0的需求爆改流水线,包括但不限于
    • 将CP0需要的已知信号统统流水传递过来,原本没有的(如表示当前指令是否为延迟槽指令的BDIn)就生成出来。
    • Controller模块中加入四条新指令即mfc0,mtc0,eret,syscall。选择合适的控制信号,个人建议syscall和eret单独拉出来。
    • 在CPU中以合适的方法建立四条新指令的数据通路。做这里的时候加吐我了,因为之前没有使用宏定义,导致很多之前不需要传递的信号都要传递。
    • 处理冒险,mfc0转发直接用原有的数据通路。阻塞则只需要加一条eret相关阻塞,处理mtc0对EPC进行写入的问题,
  4. 通过修改流水级寄存器和NPC完成异常中断的跳转和返回过程。这里我们把CP0产生的异常中断信号req传给这些模块,将流水级寄存器除了PC以外的内容置0,PC置为32'h4180,并让NPC跳转到32'h4180处,注意对实验教程中提到的对乘除模块的处理。返回则是当eret产生时,NPC跳回EPC同时清空延迟槽(操作想必大家都知道,注意阻塞的情况)。
  5. 调整模块结构,规范化CPU的输入输出端口,并建立新的mips顶层模块,将CPU和课程组给的Timer放进去。
  6. 设计Bridge模块,这个模块在P7的作用仅仅是判断当前读写的是哪个外设并处理对应的信号,实现相当简单。
  7. 把线都连好,大功告成。

功能模块设计

挑出比较重要的新增模块。

CP0

值得一提的是内部,许多学长是直接定义了IM,EXL,IE等寄存器,在写入时则用拼接的方式这是合理的,因为SR,Cause中的绝大部分位数没有用。当然,还可以使用在模块内用宏定义,具体怎么实现看个人喜好。

信号名 方向 描述 位宽
clk input 时钟信号 1
reset input 复位信号 1
en input 启用信号,控制CP0模块的操作 1
CP0Add input 控制寄存器选择信号,指定访问的寄存器地址(5位) 5
CP0In input 往CP0寄存器写入的数据 32
VPC input 异常发生时的程序计数器值 32
BDIn input 异常时的返回地址标志 1
ExcCodeIn input 异常代码 5
HWInt input 硬件中断请求信号(6位) 6
EXLClr input 清除异常级别标志(用于清除SR[1]) 1
EPCOut output 异常程序计数器(EPC)输出 32
CP0Out output 读取的CP0寄存器值,根据CP0Add选择 32
Req output 异常或中断请求信号 1

Bridge

连个线,没啥可说的。

信号名 方向 描述 位宽
Addr input 地址输入,决定访问的外设区域 32
byteen input 字节使能信号,用于指示操作的字节 4
DM_RD input 数据存储区读取数据 32
T0_RD input 定时器0读取数据 32
T1_RD input 定时器1读取数据 32
RD output 输出数据,根据地址选择不同外设的读取数据 32
DM_WE output 数据存储区写使能信号,根据地址选择是否写入数据存储区 4
T0_WE output 定时器0写使能信号 1
T1_WE output 定时器1写使能信号 1
int_WE output 中断控制寄存器写使能信号 4

关于BUG

P7真的很容易写出各种各样的BUG,所以自行测试的时候就很考验数据点编写的能力(虽然我大部分都是找别人要的)。但如果要自己编写测试点,建议先把每种类型的异常全部构造出对应的点,先检验有没有漏判的问题。随后认真观察波形图,分析一下进入异常处理程序后各寄存器的情况,以及是怎么跳转回去的,跳转回去各寄存器的情况又如何。理解好异常中断的处理过程对于找bug好处很大。

此外,评测机真的是好东西,cokiller帮我解决了大部分BUG,虽然最后还是漏了就是了。还有就是学长博客,以及多跟同学交流,很多BUG是共通的,例如空泡的问题。

测试方案

之前P3的时候想着P4再搓评测机,到后面每天疲于奔命也没有自己搓了。 于是我就自己写了一点巨弱的测试点,然后又找大佬要了一堆强力测试点。

思考题

  1. 请查阅相关资料,说明鼠标和键盘的输入信号是如何被 CPU 知晓的? 答:鼠标和键盘的输入信号通过硬件接口(如PS/2、USB或蓝牙)传输到计算机。当按下键盘的某个按键时,它会发送一个扫描码;鼠标则发送位置和点击信号。这些信号通过设备驱动程序转化为操作系统可以理解的格式,操作系统通过中断或轮询方式接收这些信号,并将其传递给相应的应用程序。最终,CPU根据这些输入信号作出响应,例如显示字符或移动鼠标指针。整个过程依赖硬件接口、驱动程序、操作系统和中断机制的协作。

  2. 请思考为什么我们的 CPU 处理中断异常必须是已经指定好的地址?如果你的 CPU 支持用户自定义入口地址,即处理中断异常的程序由用户提供,其还能提供我们所希望的功能吗?如果可以,请说明这样可能会出现什么问题?否则举例说明。(假设用户提供的中断处理程序合法) 答:因为这样可以简化设计,增加系统的稳定性和可靠性。可以提供,但是可能会出现增加安全性问题,因为用户可能会选择不够安全的入口。此外,不同程序采用不同的入口可能导致冲突,出现故障时也不容易排查Bug.

  3. 为何与外设通信需要 Bridge? 答:因为在我们的设计中,CPU不需要知道外设的具体信息,只需要对程序指定的地址进行访问。这样符合高内聚低耦合的思想。

  4. 请阅读官方提供的定时器源代码,阐述两种中断模式的异同,并分别针对每一种模式绘制状态移图。 答:区别是enable是否是自动赋值。 alt text

  5. 倘若中断信号流入的时候,在检测宏观 PC 的一级如果是一条空泡(你的 CPU 该级所有信息均为空)指令,此时会发生什么问题?在此例基础上请思考:在 P7 中,清空流水线产生的空泡指令应该保留原指令的哪些信息? 答:那么EPC会变成0,这样跳回时会引发错误。所以应该保留PC信息和本条指令是否是延迟槽的信息。

  6. 为什么 jalr 指令为什么不能写成 jalr $31, $31? 答:因为我们处理延迟槽指令发生异常时EPC会指向跳转指令,因此从异常处理程序返回后跳转指令实际上总共被执行了两次,而jalr具有累加效应,第二次执行的jalr和第一次是不一样的,所以会出错。

使用 Hugo 构建
主题 StackJimmy 设计