# CPU 设计文档及思考题

# 设计草稿

# 思路

  • 工程主要分成两个部分:IO 支持以及异常 / 中断处理,结合教程大致按照以下顺序进行实现:
    • CPU 封装
    • 添加外设 Timer
    • 实现系统桥
    • 实现协处理器 CP0
    • 异常检测和流水
    • 添加异常处理指令
    • 进行中断响应
    • 异常处理程序(mips)

# 各步实现

  • CPU 封装后与外界的接口主要是 clk,reset,IM 的地址和数据,内存空间的地址、数据和字节使能信号以及宏观 PC。另外由于输出需要还要实现 W 级各信号的接口。
  • 系统桥是纯组合逻辑模块,需要 CPU 的地址、数据、字节使能、PC 以及外设的相应信号。
    • CPU-> 外界。设置了 HitDM,HitTimer,HitInt 等信号判断输出设备 / 内存,再输出各个信号。其中最关键的是字节使能信号,例如DMByteEn=(HitDM)?ByteEn:4b0;DMByteEn = (HitDM) ? ByteEn : 4'b0;
    • 外界 ->CPU。实现 PrRD 即可。
    assign PrRD  = (HitDM)     ? DM_RD :
                     (HitTimer0) ? Timer0_RD :
      					     (HitTimer1) ? Timer1_RD :
      					     32'b0;  
    
  • CP0 设置在 M 级。CP0 可以设置在 E/M 级,考虑 store/load 类异常检测放在单独模块里比较清楚,放在了 M 级。在首次上级未通过以后发现 CP0 寄存器中大多数位为只可读
    端口方向描述
    clkinput时钟
    resetinput同步复位
    eninput写使能
    CP0Addr[4:0]input写入地址
    CP0In[31:0]input写入数据
    VPC[31:0]input受害指令 PC
    BDIninput受害指令延迟槽标记
    ExcCode[4:0]input异常类型
    HWIn[5:0]input外部中断信号
    EXLClrinputEXL 复位
    CP0Out[31:0]output读出数据
    EPCOutp[31:0]outputEPC 读出
    Reqoutput中断异常请求
    BDOutoutput延迟槽标记
  • 异常检测和流水需要在每一级添加 EXH 输入对应信号和指令信息,这里需要在原来数据通路中添加每一条指令信息,例如添加了 allCal,Store,Load 流水。以便判断是否是溢出异常 / 取指(数)异常。实现了 EXH_F,EXH_D,EXH_E,EXH_M 模块,分别检测 pc 异常,syscall 和 RI 异常,溢出异常,Load/Store 类异常。越靠前异常优先级越高。
  • 异常处理指令在原有基础上简单添加即可。按照原有方式进行译码,添加了 CP0Write 写使能信号以便支持 mfc0 工作,添 4 加 rd 流水以便支持 mt(f)c0 指令和 CP0 交互。eret 通过清空延迟槽使得不执行延迟槽指令,这个过程中的暂停 / 转发包括将 mfc0 的 T_new_D 改为 3,mtc0 的 T_use_rt 改为 2。首次上机未通过后发现 eret 与 mtc0 存在数据冒险,因此设置了 eret 的暂停信号,这也意味着出现了另一优先级的问题,即 D 级的阻塞信号优先级高于清空信号。
  • 中断请求 Req 需要传给 D,E,M,W,MDU,触发中断后全部设置为初始值。另外如 Req,则 M 级的字节使能信号应该置 0。
  • 异常处理程序直接采用模板,采取直接 + 4 跳过方式处理异常。

# 测试方案:

  • 关于指令和异常的检测,采用了之前的指令。例如 add 和 sub 的异常检测,需要检测较小数字不溢出、较大数字不溢出、溢出情况等。
  • 异常和中断指令的处理,下载了课程组提供的指令当作异常处理指令。将异常处理指令的二进制编码存到另一个文件当中以便 testbench 读入。

# 思考题:

  • 思考题 1:请查阅相关资料,说明鼠标和键盘的输入信号是如何被 CPU 知晓的?
    • 鼠标 / 键盘作为外设,映射到某个地址空间当中,通过总线连接到桥芯片,经由桥芯片和 CPU 进行交互。
    • 当鼠标 / 键盘输入时,产生中断信号,中断控制器将外设对应的中断号发送给 CPU,CPU 根据中断号找到操作系统的中断服务程序地址,进入对应中断服务程序完成相应工作。其中采用了 MMU 技术使得外设与 CPU 的交互无需经由主存。
  • 思考题 2:请思考为什么我们的 CPU 处理中断异常必须是已经指定好的地址?如果你的 CPU 支持用户自定义入口地址,即处理中断异常的程序由用户提供,其还能提供我们所希望的功能吗?如果可以,请说明这样可能会出现什么问题?否则举例说明。(假设用户提供的中断处理程序合法)
    • 中断异常处理的流程固定。因此统一中的断处理程序有助于全面覆盖各种情况,保证处理的统一性和正确性。
    • 本 CPU 未实现用户自定义中断处理功能。但支持自定义的 CPU 应该可以实现。如果实现了自定义中断入口的 CPU,其中断处理的灵活性更好,但是可能导致系统更加复杂。
  • 思考题 3:为何与外设通信需要 Bridge?
    • 外设数量和种类众多,如果直接用 CPU 和各个外设相连,那么系统的可读性和清晰性得不到保证,也不易于进行扩展。将外部通信功能提取出来统一交给桥芯片实现,符合了高内聚低耦合的原则,使得 CPU 可以将所有外设都当成内存空间进行处理,统一性好。
    • 外设的通信方式各不相同,并且地址空间可能重合,桥芯片承担了转换交互信号和地址信息的功能。在实际实现中,还分为北桥芯片和南桥芯片。前者负责 CPU 和主存 / 显卡的连接,后者负责前者与各种 I/O 设备的连接。
  • 思考题 4:请阅读官方提供的定时器源代码,阐述两种中断模式的异同,并针对每一种模式绘制状态移图。
    • 相同之处是都使用了初值寄存器、计数器、控制寄存器,其中中断屏蔽行为相同,也都是在 count 为 0 时产生中断信号。
    • 不同之处是模式 0 在完成计数时 Enable 置 0,不再计数,持续产生中断信号,直到 Enable 被外部修改为 1;而模式 1 完成计数后产生一个周期中断就再进行一轮计数,用于产生周期性中断。
    • 以 preset 为 3 为例,状态转移图如下:
      图 1
  • 思考题 5:倘若中断信号流入的时候,在检测宏观 PC 的一级如果是一条空泡(你的 CPU 该级所有信息均为空)指令,此时会发生什么问题?在此例基础上请思考:在 P7 中,清空流水线产生的空泡指令应该保留原指令的哪些信息?
    • 如果是一条空泡,则会将 0x00000000 当作宏观 PC 写入 EPC 当中,这会导致中断处理完成以后回不到当前位置上。
    • PC 和 BD 两个信号在插入空泡时应该保留被暂停指令的值。保留 PC 的原因如上所述,而保留 BD 则是因为当空泡遇到中断时,如 BD 不保留,则无法判断当前被暂停(将要执行)的指令是否是延迟槽指令。如果是延迟槽指令且 BD 被置零,那么前一条跳转指令就失效了。
  • 思考题 6:为什么 jalr 指令为什么不能写成 jalr $31, $31?
    • jalr 指令读取 rs 寄存器,写到 rd 寄存器。当 jalr 指令的延迟槽遇到中断时,jalr 执行完毕,再进行中断处理程序,此时 31 号寄存器已经被 jalr 修改,等到处理结束回到 jalr 重新执行时,jalr 读到的 $31 是已经被自己修改的,会导致执行错误。
更新于

请我喝[茶]~( ̄▽ ̄)~*

Zeng Huaxu 微信支付

微信支付

Zeng Huaxu 支付宝

支付宝