设计思路

在P6基础上,进行如下修改。

异常中断

  • 添加模块CP0
  • 添加指令:eret,syscall,mtc0,mfc0
    • mfc0指令激活RegWrite与特殊写使能,t设置为2
    • mtc0的t_rt设置为2
    • eret对应信号与CP0的EXCClr连接
  • 修改各级部件以支持异常检测
    • F级:PC错误
    • D级:指令错误/syscall
    • E级:加减溢出,Load/Store地址范围错误
    • 所有异常流入M级的CP0中
    • 注意流水的优先级顺序,设置各级fixedExcCode信号
  • 修改各级部件以支持异常中断
    • F级检测到pc异常,则将IM导入的instr清空
    • npc在Req激活时跳转到0x00004180
    • 各级pc修改为0x00004180
    • 各级流水寄存器清空
    • CP0进行若干操作:
      • 异常后EPCout设置为受害PC-4(延迟槽指令),或PC
      • 中断优先级更高,若检测到中断信号,ExcCode设置为0

系统架构

  • 将mips改为CPU,修改input和output信号
  • 增加Bridge模块,加入Timer0,Timer1
  • 增加新的顶层mips模块,包含CPU,Bridge,Timer0,Timer1模块

测试方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
.text
# 初始化
li $s0, 0x7f00 # Timer0 基地址
li $s7, 0 # 用于观察 ExcCode

# 1. 测试 Ov (ExcCode=12)
li $t0, 0x7fffffff
addi $t0, $t0, 1

# 2. 测试 Syscall (ExcCode=8)
syscall

# 3. 测试 RI (ExcCode=10)
.word 0xFFFFFFFF

# 4. 测试 AdEL (ExcCode=4)
lw $t1, 1($0) # 地址未对齐
lh $t1, 8($s0) # 非法读取 Timer Count

# 5. 测试 AdES (ExcCode=5)
sw $t1, 2($0) # 地址未对齐

# [关键测试] 向 Timer Count 写值 -> 必须触发 AdES
# 如果这里没触发异常,$s7 不会变成 5,且计时器会被错误修改
li $t2, 100
sw $t2, 8($s0)

# 6. 测试 Int (ExcCode=0)
li $t1, 50
sw $t1, 4($s0) # 设置 Preset
li $t1, 0xB # 1011 (IntEn | Enable)
sw $t1, 0($s0) # 设置 Ctrl

# 开启 CP0 中断 (IE=1, IM=Timer0)
mfc0 $t0, $12
ori $t0, $t0, 0x0401
mtc0 $t0, $12

loop:
j loop # 等待中断
nop

# 异常处理程序 (0x4180)
.ktext 0x4180
# 获取并保存 ExcCode 到 $s7
mfc0 $k0, $13
srl $k0, $k0, 2
andi $k0, $k0, 0x1f
move $s7, $k0

# 判断是中断还是异常
beq $k0, $0, is_int
nop

is_exc:
# 异常:EPC += 4 跳过指令
mfc0 $k1, $14
addiu $k1, $k1, 4
mtc0 $k1, $14
eret

is_int:
# 中断:关闭 Timer 防止死循环
li $k0, 0x7f00
sw $0, 0($k0)
eret

思考题

  • 请查阅相关资料,说明鼠标和键盘的输入信号是如何被 CPU 知晓的?
    • 硬件设备生成信号,通过接口控制器传递给CPU,CPU进行中断处理或轮询读取数据。
  • 请思考为什么我们的 CPU 处理中断异常必须是已经指定好的地址?如果你的 CPU 支持用户自定义入口地址,即处理中断异常的程序由用户提供,其还能提供我们所希望的功能吗?如果可以,请说明这样可能会出现什么问题?否则举例说明。(假设用户提供的中断处理程序合法)
    • 理论上可行。但实际会因为编写代码可能存在的漏洞导致系统的安全性风险增加,稳定性降低。
    • 支持动态地址会增加性能和管理的开销。
  • 为何与外设通信需要 Bridge?
    • 主机和外设之间存在接口标准,速度贷款,数据格式等各种差异,需要Bridge从中进行协调。
  • 请阅读官方提供的定时器源代码,阐述两种中断模式的异同,并针对每一种模式绘制状态移图。
    • 模式0(单次):减到0后停止,产生一次终端。需软件手动重置才能再次计数。
    • 模式1(循环):减到0后自动重装初值,产生周期性中断。
  • 倘若中断信号流入的时候,在检测宏观 PC 的一级如果是一条空泡(你的 CPU 该级所有信息均为空)指令,此时会发生什么问题?在此例基础上请思考:在 P7 中,清空流水线产生的空泡指令应该保留原指令的哪些信息?
    • 问题:如果中断发生时M级是空泡(PC=0),CP0会保存错误的EPC=0。执行eret返回时 CPU 会跳到0地址,导致崩溃。
    • 保留PC信号,确保EPC指向正确的返回地址。
  • 为什么 jalr 指令为什么不能写成 jalr $31, $31?
    • 读写冲突。jalr需要跳转到$31中的地址,同时将PC+8存入$31,如果源和目的都是$31,写入返回地址(PC+8)的操作可能会覆盖掉目标跳转地址,导致 CPU 跳到了下一条指令而不是目标函数,程序逻辑出错。