计组P7设计文档

P7建议:先理解异常的处理过程,明确需要硬件完成是哪一部分,然后逐步搭建。(异常的处理和系统桥感觉相对独立?)

源代码:solor-wind/BUAA_CO (github.com)

设计要求、架构与需求

设计要求

处理器应为五级流水线设计,支持如下指令集:

1
2
3
4
5
6
add, sub, and, or, slt, sltu, lui
addi, andi, ori
lb, lh, lw, sb, sh, sw
mult, multu, div, divu, mfhi, mflo, mthi, mtlo
beq, bne, jal, jr
mfc0,mtc0,eret,syscall

其他详见“P7提交要求”

任务需求

说实话,P7的教程给出了大致框架,但很多地方的细节并未给出,或者分散在不同地方(不同章节、SMRL、设计文档等),难以明确需求与任务要求,从而导致实现困难,下面是个人的总结。

术语的明确

  • 内部异常:指由于执行指令引发的异常,如算术溢出、地址未对齐等等
  • 外部中断:指外部引发的中断,如计时器、tb给出的中断信号等等
  • 异常/中断:以上两类事件的统称

任务

核心任务:实现异常的处理
处理步骤
  1. 根据当前CP0的SR状态、内部异常exc信号、外部中断HWint信号判断是否中断
  2. 把宏观PC写入EPC(注意延迟槽指令),异常信息写入CP0的Cause寄存器,SR相应位置1进入内核态(处理中断过程中禁止嵌套中断)
  3. 将PC调整到0x4180,清空宏观PC及之前的流水线寄存器
  4. 执行异常处理程序(处理异常、响应中断、回到原来指令等操作都交给软件实现)
具体实现
  • 每一级新增异常判断,流水异常信号——对应步骤1
  • 每一级新增中断信号,进行清空操作——对应步骤2
  • 每一级针对新增的指令进行修改(要结合CP0的设计一起进行),完成阻塞和转发的修改——对应步骤4
  • CP0的实现,包括接受内部异常与外部中断信号、给出中断信号、实现对三个寄存器的写入与读出。
一些细节
  • CP0位置:我选择在E级,此时已经可以判断出所有类型,并且不会对乘除模块的寄存器、DM与外设、寄存器堆进行写入,同时可以参考乘除模块进行转发与阻塞的处理
  • 延迟槽的判断:直接引入M级指令,若M为跳转,则判断为延迟槽
  • 优先级:复位信号>外部中断>内部异常,这体现在Cause寄存器写入等方面
  • HWint={3'b0,interrupt,timer0,timer1} (看了学长的博客才知道,根本没有6个中断)
附属任务:将CPU封装为单周期,实现与外设沟通的系统桥
封装为单周期

考察CPU的功能,主要有以下几点:

  • 执行指令进行计算——需要IM接口(提供pc,获取指令)
  • 与外设进行读、写操作——需要DM等接口(提供addr、写入数据,获取读出数据)
  • 获取外部中断信号——2个timer和tb的中断
  • 老2样——clk与reset
  • 课程组检查寄存器的入口——寄存器堆相关信号
系统桥

考察系统桥的功能,就是根据M级指令、地址、数据,向外设提供相应的写使能信号、写入数据,同时对来自外设的数据进行选择。因此,接口应该能实现以上功能。

架构

微系统架构.png

模块规格

命名规则

流水线信号共5级,IF/ID ID/EX EX/MEM MEM/WB,两个寄存器间的信号用 级别_数据/功能_去向 命名。

CPU

封装

变量 方向 位宽 解释 来源/去向
clk in 1 时钟信号 tb
reset in 1 复位信号 tb
int_export in 1 外部中断信号 tb
int_timer0 in 1 时钟中断信号0 Timer0
int_timer1 in 1 时钟中断信号1 Timer1
macroscopic_pc out [31:0] 宏观pc EX/tb
i_inst_rdata in [31:0] IM的指令 IF_instr
i_inst_addr out [31:0] IF的pc IF_pc
w_grf_we out 1 WB tb
w_grf_addr out [4:0] WB tb
w_grf_wdata out [31:0] WB tb
w_inst_addr out [31:0] WB tb
m_inst_addr out [31:0] M级pc EX_pc_MEM/bridge
out_instr out [31:0] 写入外设的指令 EX_instr_MEM/bridge
out_addr out [31:0] 写入外设的地址 EX_out/bridge
out_WD out [31:0] 写入外设的数据 EX_rt_MEM或W级转发
out_RD in [31:0] 从外设读取的数据 MEM_data

模块共有信号:

变量 方向 位宽 解释 来源/去向
clk in 1 时钟信号 顶层输入
rst in 1 复位信号 顶层输入
xx_pc in [31:0] 当前级的pc 上一级(IF为out)
xx_pc_yy out [31:0] 要传给下一级的pc 下一级yy(WB无)
xx_instr in [31:0] 当前级的指令 上一级
xx_instr_yy out [31:0] 要传给下一级的指令 下一级yy(WB无)

IF

变量 方向 位宽 解释 来源/去向
req in 1 中断信号,跳至0x4180 CP0
stall in 1 阻塞信号,使pc保持不变 staller
IF_j in 1 是否跳转 ID_j_IF
IF_pc4 in [31:0] 跳转指令地址 ID_pc_IF
IF_instr in [31:0] 从tb获取的指令 tb
IF_pc out [31:0] IF级当前指令 tb
IF_exc_ID out [31:0] 内部异常信号 ID

ID

接口
变量 方向 位宽 解释 来源/去向
req in 1 中断信号,清空D级 CP0
stall in 1 阻塞信号,清空D级 staller
EPC in [31:0] CP0的EPC EX_rt(转发)、CP0
WB_pc_ID in [31:0] 写入指令的pc WB_pc_ID
ID_we in 1 寄存器写入信号 WB_we_ID
ID_addr in [4:0] 要写入的寄存器 WB_addr_ID
ID_data in [31:0] 要写入的值 WB_data_ID
ID_rs_sign in [2:0] 转发选择,0为原值
ID_rt_sign in [2:0] 转发选择,0为原值
ID_rs_data in [31:0] 转发值 EX_out,EX_data_WB,MEM_data_WB
ID_rt_data in [31:0] 转发值
ID_exc in [31:0] IF的异常信号 IF
ID_exc_EX out [31:0] 给EX的异常信号 EX
ID_rs_base out [31:0] rs寄存器的值 EX_rs_base
ID_rt out [31:0] rt寄存器的值 EX_rt
ID_j_IF out 1 跳转指示信号 IF_j
ID_pc_IF out [31:0] 跳转指令地址 IF_pc4
内部变量与操作
1
2
3
wire [31:0] ID_rs_use;//搭配转发使用
wire [31:0] ID_rt_use;//搭配转发使用
reg [31:0] grf [0:31];//32个寄存器

EX

接口
变量 方向 位宽 解释 来源/去向
req in 1 中断信号,清空本级 CP0
EX_rs_base in [31:0] rs寄存器的值 ID_rs_base
EX_rt in [31:0] 参与运算的rt寄存器的值,可能从转发处来
EX_CP0 in [31:0] 从CP0读取的值 CP0
EX_exc in [31:0] 从ID流水下来的内部异常信号 ID
EX_exc_CP0 out [31:0] 传给CP0的内部异常信号 CP0
EX_new out 1 表示E级产生了新的要写入寄存器的值 instr
EX_addr out [4:0] E级产生新值的寄存器地址 instr
EX_out out [31:0] 运算结果 MEM_addr
EX_rt_MEM out [31:0] rt寄存器的值 MEM_data
busy out 1 mul是否正忙 mul
内部变量
1
2
3
4
5
6
reg [31:0] out;//即时给出运算结果,上升沿时赋给EX_out
reg [31:0] EX_tmp_new;//同上,EX_new
reg [4:0] EX_tmp_addr;//EX_addr
wire [2:0] start;//从E级指令给出mul所需信号,req时为0
wire [31:0] hi;//
wire [31:0] lo;
内部模块——mul
变量 方向 位宽 解释 来源/去向
clk in 1 时钟信号 EX
rst in 1 复位信号 EX
start in [2:0] 开始运算信号 EX
A in [31:0] 运算数rs EX_rs_base
B in [31:0] 运算数rt EX_rt_use
busy out 1 正忙信号 busy
hi out [31:0] 乘法高位/除法余数 out
lo out [31:0] 乘法低位/除法的商 out

MEM

接口
变量 方向 位宽 解释 来源/去向
MEM_addr in [31:0] 要读出的地址 EX_out
MEM_data in [31:0] 读出的数据 bridge
MEM_new out 1 表示M级有了新的要写入寄存器的值 instr
MEM_new_addr out [4:0] M级新值的寄存器地址 instr
MEM_data_WB out [31:0] 传向下一级的数据 WB_lw_data
EX_data_WB out [31:0] 运算结果 WB_alu_data
内部变量
1
2
reg [2:0] op;//位扩展选择信号
wire [31:0] data_out;//原始读出数据
内部模块——ext
变量 方向 位宽 解释 来源/去向
A in A 读出地址的低位 MEM_addr
Din in Din 原始数据 MEM_data
Op in Op 扩展选择信号 op
Dout out Dout 扩展后的数据 MEM_data_WB

WB

输出均不是reg型

变量 方向 位宽 解释 来源/去向
WB_lw_data in [31:0] 从内存取出的数 MEM_data_WB
WB_alu_data in [31:0] 运算结果 EX_data_WB
WB_we_ID out 1 寄存器写入信号 ID_we
WB_addr_ID out [4:0] 要写入的寄存器地址 ID_addr
WB_data_ID out [31:0] 要写入寄存器的值 ID_data

CP0

位于E级,此时已经可以判断出所有异常类型,而且不会写入乘除模块、DM以及寄存器

通过E级指令来写入/读出相应寄存器,读出/写入的值与E级其他指令一样流水

变量 方向 位宽 解释 来源/去向
clk in 1 时钟信号 tb
rst in 1 复位信号 tb
HWint in [5:0] 输入中断信号 tb
exc in [31:0] 异常类型 EX_exc_CP0
EX_pc in [31:0] E级pc EX
EX_instr in [31:0] E级指令 EX
MEM_instr in [31:0] M级指令,判断延迟槽 EX_instr_MEM
EX_rt in [31:0] 写入CP0的数据 EX_rt
CP0_rd out [31:0] 从CP0读出的数据 EX_CP0
EPC out [31:0] EPC IF
Req out 1 中断信号 好多
寄存器对应位的功能

其中,SR编号12,Cause编号13,EPC编号14

寄存器 功能域 位域 解释
SR(State Register) IM(Interrupt Mask) 15:10 分别对应六个外部中断,相应位置 1 表示允许中断,置 0 表示禁止中断。这是一个被动的功能,只能通过 mtc0 这个指令修改,通过修改这个功能域,我们可以屏蔽一些中断。
SR(State Register) EXL(Exception Level) 1 任何异常发生时置位,这会强制进入核心态(也就是进入异常处理程序)并禁止中断。
SR(State Register) IE(Interrupt Enable) 0 全局中断使能,该位置 1 表示允许中断,置 0 表示禁止中断。
Cause BD(Branch Delay) 31 当该位置 1 的时候,EPC 指向当前指令的前一条指令(一定为跳转),否则指向当前指令。
Cause IP(Interrupt Pending) 15:10 为 6 位待决的中断位,分别对应 6 个外部中断,相应位置 1 表示有中断,置 0 表示无中断,将会每个周期被修改一次,修改的内容来自计时器和外部中断。
Cause ExcCode 6:2 异常编码,记录当前发生的是什么异常。
EPC - - 记录异常处理结束后需要返回的 PC。
异常码
异常与中断码 助记符与名称 指令与指令类型 描述
0 Int (外部中断) 所有指令 中断请求,来源于计时器与外部中断。
4 AdEL (取指异常) 所有指令 PC 地址未字对齐。
PC 地址超过 0x3000 ~ 0x6ffc
AdEL (取数异常) lw 取数地址未与 4 字节对齐。
lh 取数地址未与 2 字节对齐。
lh, lb 取 Timer 寄存器的值。
load 型指令 计算地址时加法溢出。
load 型指令 取数地址超出 DM、Timer0、Timer1、中断发生器的范围。
5 AdES (存数异常) sw 存数地址未 4 字节对齐。
sh 存数地址未 2 字节对齐。
sh, sb 存 Timer 寄存器的值。
store 型指令 计算地址加法溢出。
store 型指令 向计时器的 Count 寄存器存值。
store 型指令 存数地址超出 DM、Timer0、Timer1、中断发生器的范围。
8 Syscall (系统调用) syscall 系统调用。
10 RI(未知指令) - 未知的指令码。
12 Ov(溢出异常) add, addi, sub 算术溢出。

Bridge

变量 方向 位宽 解释 来源/去向
MEM_instr in [31:0] M级指令 CPU
MEM_addr in [31:0] M级要读/写的地址 CPU
MEM_WD in [31:0] M级要写入的数据 CPU
MEM_RD out [31:0] 传给M的从外设读取的数据 CPU
WD out [31:0] 传给外设的写入的数据 CPU
DM_RD in [31:0] 从DM读出的数据 tb
m_data_byteen out [3:0] DM写使能 tb
m_int_byteen out [3:0] 外部中断写使能 tb
Timer0_RD in [31:0] Timer0读出的数据 Timer0
Timer0_we out 1 Timer0写使能 Timer0
Timer1_RD in [31:0] Timer1读出的数据 Timer1
Timer1_we out 1 Timer1写使能 Timer1

主要功能:根据从M级的指令、地址、数据,给出相应的读写信号、写入数据的预处理、读出数据的选择

Timer

冒险处理

新增了E级到D级的转发(eret)

mfc0采用之前的转发就好

mtc0采用之前的转发就好

转发

转发共5个接受:

1
2
3
4
5
wire [31:0] ID_rs_data;
wire [31:0] ID_rt_data;
wire [31:0] EX_rs_base;
wire [31:0] EX_rt;
wire [31:0] MEM_data;

共2处提供:

1
2
wire [31:0] EX_out;
wire [31:0] WB_data_ID;

其中,2处提供接口还给出new信号与addr,代表新值产生且可用、要写入的寄存器编号

接受者只需判断new与addr即可决定转发与否(有新值且可用就转发)

阻塞

\(T_{use}\)\(T_{new}\) 的计算见表格

采用Time模块传递计算结果,[31:0] use_new 具体每位对应结果如下表

[2][1][0]分别对应rs、rt、rd

rs rt rd [4] [2] [1] [0]
-> use或new的数值 <- 1代表正在算乘除法 -> 0为use,1为new <-

\(T_{use}<T_{new}\) ,或乘除类指令遇上busy,则执行阻塞操作:

  1. 冻结IF/ID
  2. 清除ID/EX
  3. 禁止PC

注意事项

  • 从W级转发到D级,采用D级内部转发(如beq)
  • 转发时如果地址是0寄存器应剔除

添加指令

  1. 添加到const、IF已有指令里

  2. 填写TIME表格,根据use和new更改M级中的MEM_new与MEM_new_addr,添加Time中的use与new值

  3. 根据操作在每个模块添加行为

    • IF:指令获取与延迟槽、未知指令与取指异常
    • ID:给出跳转指令
    • EX:各种计算行为、存储地址计算
    • MEM:给出写入内存的地址、转发信号、对读出的数据进行加工
    • WB:给出写寄存器信号、寄存器编号、数据
    • Bridge:sw类指令给出使能信号判断
  4. 每类指令对应行为(P5)

    • cal:修改EX计算过程、添加WB回写信号,加入相关阻塞指令中(带cal的),加入相关转发指令中(同上,注意供需接口都有)。
    • lw:修改EX计算过程、添加WB回写信号,……
    • sw:修改EX计算过程、Bridge使能判断、MEM写入,………
    • j:修改ID跳转判断与跳转地址计算,加入阻塞、转发指令
    • jal:修改ID跳转判断与跳转地址计算、EX算pc等、WB回写信号,阻塞转发
  5. 是否有新的转发通路、阻塞可能

思考、bug与测试

思考题

  1. 请查阅相关资料,说明鼠标和键盘的输入信号是如何被 CPU 知晓的?

    当键盘、鼠标有输入时(状态更新或其他),向CPU发出中断信号,CPU接到中断信号后判断中断种类,并执行相应区域代码,完成输入信号的读取。其中,输入信号需要驱动程序的解读。

  2. 请思考为什么我们的 CPU 处理中断异常必须是已经指定好的地址?如果你的 CPU 支持用户自定义入口地址,即处理中断异常的程序由用户提供,其还能提供我们所希望的功能吗?如果可以,请说明这样可能会出现什么问题?否则举例说明。(假设用户提供的中断处理程序合法)

    必须是已经指定好的地址。处理中断异常程序的目的是维护系统、程序的正常运行,并返回错误信息。如果地址由用户自定义,可能地址无效产生新的异常、或处理程序也产生新的异常等,达不到目的。

  3. 为何与外设通信需要 Bridge?

    外设种类很多而CPU指令集有限,因此要把外设的接口和CPU的接口通过系统桥连接起来,通过统一的方式,由系统桥选择相关信息的输入输出。

  4. 请阅读官方提供的定时器源代码,阐述两种中断模式的异同,并针对每一种模式绘制状态移图。

    计时器状态转换图

    state的状态转换其实 一样,区别在于从INT到IDLE这一步。

    模式0将ctrl[0]置0,IRQ仍然为1,让state在IDLE卡死

    模式1将IRQ置0,ctrl[0]仍然为1,让state能继续由IDLE到LOAD,顺便在这一过程中把IRQ置0,实现循环

  5. 倘若中断信号流入的时候,在检测宏观 PC 的一级如果是一条空泡(你的 CPU 该级所有信息均为空)指令,此时会发生什么问题?在此例基础上请思考:在 P7 中,清空流水线产生的空泡指令应该保留原指令的哪些信息?

    EPC会存入0,跳转回正常指令的时候出错。pc、错误信息

  6. 为什么 jalr 指令为什么不能写成 jalr $31, $31

    根据MARS的行为,jalr两个寄存器相同会导致先写入当前pc+4,再从寄存器取数跳转,实际上达不到跳转到$31的目的

  7. [P7 选做] 请详细描述你的测试方案及测试数据构造策略。

    详见“测试部分”

写P7遇到的bug

eret的跳转值要接受来自mtc0(E级)的转发,还要判断地址是不是EPC

ID在中断时写寄存器操作不能停(相当于W级)

未知指令少打了个sb、mtc0的指令编码敲错了

计数器之间的地址不连续

外部异常比内部异常优先写入Cause

stall和req时应当保持pc

判断溢出的实现有误,应严格按MARS文档来

不管跳转指令是否跳转,其后的延迟槽指令都必须携带BD标记

写入外设的数据和DM提前准备好的冲突

应流水延迟槽标记,而非通过M级判断

阻塞、中断的时候没管BD

测测延迟槽阻塞、中断(已测)

外部中断的时候,BD需要置1吗——需要

SR的IP要每周期修改一次

mtc0和mfc0如果超出12-14怎么办——不用管

何时复位EXL——eret到CP0的下一上升沿

取值异常或RI后视为nop提交至CP0

未知指令判断时,mtc0?、

在延迟槽中断后,修改pc使得在延迟槽重新执行,BD需要置1吗?——不需要

eret处中断怎么办——不会出现tb中断

从中断发生器(不是计时器)读出的数据应该保持0

CP0部分位是只读,未使用的位应当保持为0!!!

通过sw相应一些中断时,阻塞阻塞再eret?、

mtc0、mfc0的rt和rd不要混!!!

D/E流水线寄存器在阻塞的时候应当流水上一级pc和BD!!!

好奇:课程组到底是怎么测试时钟中断的?

优化:lui提前至D级实现、取消对0寄存器的阻塞

测试部分

1
2
3
4
5
6
7
8
9
10
11
ori $4,$0,4
sw $4,-4($4)
lw $2,0($0)
sw $2,0($2)s

ori $2,$2,4
ori $3,$3,8
ori $4,$4,12
sw $2,0($0)
sh $3,6($0)
sb $4,11($0)
part1——P4的数据测试
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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
.data
.space 0x3000
.text
ori $0,$0,0
ori $2,$0,2
ori $3,$0,3
ori $4,$0,4
ori $5,$0,5
ori $6,$0,6
ori $7,$0,7
ori $8,$0,8
ori $9,$0,9
ori $10,$0,10
ori $11,$0,11
ori $12,$0,12
ori $13,$0,13
ori $14,$0,14
ori $15,$0,15
ori $16,$0,16
ori $17,$0,17
ori $18,$0,18
ori $19,$0,19
ori $20,$0,20
ori $21,$0,21
ori $22,$0,22
ori $23,$0,23
ori $24,$0,24
ori $25,$0,25
ori $26,$0,26
ori $27,$0,27
ori $28,$0,28
ori $29,$0,29
ori $30,$0,30
ori $31,$0,0x310c


ori $0,$0,1#$0应始终为0
ori $2,$0,65535
ori $3,$0,0
ori $4,$0,12
lui $5,65535
lui $6,0
lui $7,8
add $8,$5,$2#-1
lui $9,32767
add $9,$9,$2#intmax
add $10,$9,$8
sub $10,$8,$9#-intmax-1
add $10,$0,$10
sub $11,$2,$4#65523
sub $12,$4,$2#-65523
add $13,$11,$12#0
sub $14,$5,$5#0

lui $18,0
ori $18,$18,0x2ffc
sw $10,($18)
sw $11,12280($0)
sw $12,-4($4)#8
lw $15,8($0)#$12,-65533
lw $16,12284($0)#$10,-intmax-1
lw $17,12280($0)#11,65523

loop:
lui $21,0
ori $21,$21,1
add $19,$19,$21
beq $19,$20,loop#$19=21跳出

sub $22,$0,$20#$22=-20
loop2:
beq $22,$20,loop2
add $22,$0,$20
beq $22,$20,end
nop
end:
add $23,$23,$21

loop3:
jr $ra
nop
jal loop3#往前跳
nop
jal loop4#往后跳
loop4:
nop
beq $24,$21,end2
add $24,$0,$21
add $25,$0,$ra
jr $25
end2:
nop
jal end2#原地蹦跶
nop
part2——p5冒险测试

\(A_9^4\)

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
#add,sub,ori,lui,lw,sw,beq,jal,jr
#先把每个寄存器里的值搞成非0
add $2,$2,$2
add $2,$2,$2
sw $2,-4($2)
sub $3,$2,$2
ori $2,$3,8
lw $4,4($0)
sub $5,$4,$2

lui $6,1
ori $6,$6,1
sw $6,0($0)
lw $7,0($0)
ori $7,$7,2

lw $8,0($0)
sw $8,8($0)

loop:
add $9,$10,$9
beq $9,$19,loop
ori $11,$0,1
jal loop2
add $12,$11,$11
loop2:
sw $ra,12($0)
ori $ra,$0,0
lw $30,12($0)
jr $30
nop
part3——p6新增指令测试

重点测试边缘数据

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
and $1,$2,$2
or $3,$4,$3
sub $5,$5,$6
slt $7,$5,$6
sltu $8,$5,$6
addi $9,$9,-1
andi $10,$10,-1
sb $11,-1($4)
sh $11,0($0)
lw $12,0($0)
lui $11 0x1111
ori $11 0x1111
sh $11,2($4)
lb $13,3($4)
lh $14,2($4)

mult $11,$4
mfhi $15
multu $11,$4
mfhi $16
div $11,$4
mflo $17
divu $11,$4
mflo $18
mthi $19
mtlo $20

lui $20,0
ori $20,1
loop:
bne $19,$21,loop
sub $21,$21,$20
nop
#重点测试符号乘除
lui $2,0x1111
ori $2,$2,0x1111
add $3,$2,$0
mult $2,$3
mfhi $4
mflo $5
multu $2,$3
mfhi $6
mflo $7

ori $8,$0,13
add $2,$2,$8
div $2,$8
mfhi $9
mflo $10
div $8,$2
mfhi $11
mflo $12
div $2,$3
mfhi $13
mflo $14
divu $2,$8
mfhi $15
mflo $16
divu $8,$2
mfhi $17
mflo $18
divu $2,$3
mflo $19
mflo $20

part4——p7中断异常测试

异常全覆盖

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
67
68
69
70
71
72
ori $1,$1,0x1c01
mtc0 $1,$12

#pc地址未对齐
ori $2,$2,0x300a
jr $2
add $2,$2,$2#顺便延迟槽
#pc地址超范围
jr $2
ori $3,$3,0x0003

#lw、lh没有字对齐
lw $2,0($3)
lh $2,1($0)
#lh、lb取Timer寄存器的值
ori $4,$4,0x7f00
lw $5,0($4)#应该没错
lh $5,0($4)
lb $5,20($4)
#计算地址加法溢出
lui $6,65535
ori $6,$6,65535
lw $7,1($6)
#取数地址超出范围
ori $7,0x7f0c
lw $7,0($7)

#sw、sh没有字对齐
sw $2,0($3)
sh $2,1($0)
#sh、sb取Timer寄存器的值
sw $5,0($4)#应该没错
sh $5,0($4)
sb $5,20($4)
#计算地址加法溢出
lui $6,65535
ori $6,$6,65535
sw $7,1($6)
#向计时器Count寄存器存值
sw $7,-4($7)
#存数地址超出范围
sw $7,100($7)

#syscall
syscall

#RI
nor $2,$3,$4

#算术溢出
addi $1,$0,1
sub $8,$0,$1
add $9,$8,$6#不应溢出
sub $9,$6,$8#溢出
add $9,$6,$7#溢出
sub $9,$0,$6
addi $9,$9,-100#溢出


end:
beq $0,$0,end#死循环
nop

#异常处理程序
.ktext 0x4180
mfc0 $k0,$12
mfc0 $k0,$13
mfc0 $k0,$14
addi $k0,$k0,4
mtc0 $k0,$14
eret
add $2,$2,$2#应当没有延迟槽

中断、异常、阻塞、延迟槽交错,限制部分中断

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
ori $1,$1,0x1c01
mtc0 $1,$12

lui $2,0x7fff
lui $3,0x7fff
beq $0,$3,end
add $2,$3,$3#延迟槽指令出错。可在此处加入外部中断,断2次

ori $4,$4,4
lw $4,-4($4)#阻塞的时候来点外部中断
bne $0,$4,end#此处需要更改机器码让beq出错
ori $4,$2,1

#时钟中断
ori $5,$0,9
ori $8,$0,1
ori $6,$0,0x7f00
sw $8,4($6)
sw $5,0($6)
add $7,$7,$5#啥时候中断我也搞不清……
add $7,$7,$5
add $7,$7,$5
add $7,$7,$5

and $1,$1,$0
ori $1,$1,0x1001
mtc0 $1,$12#不许时钟中断了
sw $8,4($6)
sw $5,0($6)
add $7,$7,$5#啥时候中断我也搞不清……
add $7,$7,$5
add $7,$7,$5
add $7,$7,$5

end:
beq $0,$0,end#死循环
nop


#异常处理程序
.ktext 0x4180
mfc0 $k0,$12
mfc0 $k0,$13
ori $k1, $0, 0x7c
and $k0, $k0, $k1
bne $k0,$0,WTF
sb $0, 0x7f20($0)
sw $0, 0x7f00($0)
WTF:
mfc0 $k0,$14
addi $k0,$k0,4
mtc0 $k0,$14
eret

计组P7设计文档
https://solor-wind.github.io/2024/01/23/计组P7设计文档/
作者
gpf
发布于
2024年1月23日
许可协议