计算机系统(1) 实验五 中断实验
一、实验目的
本实验的目的是展示在LC-3中如何让输入输出通过执行中断处理程序的方式来暂停和恢复一个正在运行的程序,恢复后的程序就像中间什么都没有发生过,本实验使用键盘作为输入来中断正在运行的程序。
二、实验背景及要求
(一)实验背景:
计算机领域中,中断就是由软硬件向处理器发送信号,处理器收到并立即处理该信号表示事件的过程。中断会暂停当前处理器正在执行的流程,然后将处理器切换到高优先级。处理器会暂存当前任务的状态,然后执行一小段称为中断处理程序(ISR)的代码来处理该事件。中断是暂时的,中断处理程序执行结束后,处理器会回到之前任务暂存的状态继续执行,中断分为两种类型:硬件中断和软件中断。
(二)实验要求:实现三部分程序
1.用户程序:
实现:该程序持续间隔的输出两行不同的“ICS”
2.键盘中断处理程序:
该程序每次简单的把用户键入的回车(x0A)之前的字符打印10次。在中断处理程序中,TRAP指令是不能使用的,当需要显示字符时,必须通过读写DSR的方式,也不能用TRAP x21(OUT)和其他的TRAP指令。在中断处理程序中要对用到的寄存器的状态暂存和恢复。
注:编写DELAY子程序:为了不让屏幕太快的输出以至于看不清每行的内容,该程序需要嵌入一段计数代码,每次从2500递减到0,计数完成,然后输出一行
3.操作系统使能代码:
因为LC-3上还不能安装Windows 和 Linux ,所以如下工作需要在用户程序中首先完成:
A、通常情况下,当遇到中断发生之前,操作系统已经开辟好栈空间,保存PC和PSR,当执行到RTI时,PC和PSR会被弹栈,因为没有操作系统,需要初始化R6为X3000,指示一个空栈。
B、本实验的键盘中断处理程序需要你来做,中断向量表的起始地址为X0100,键盘中断处理程序的起始地址为X80
C、最后,需要把KBSR的IE(Interrupt Enable) 位置1
三、实验步骤
1.分析和理解指定的需解决问题:
根据要求,实验设计思路如下:
(1)编写用户程序思路:
①初始化栈指针R6为x3000,重新设置键盘中断,修改键盘中断号x0180的内容,以及将KBSR的IE位置为1,支持中断
②调用系统输出函数PUTS,同时调用子程序DELAY,分别输出两行字符串“ICS ”,“ ICS”,分别循环6次和5次
③编写DELAY子程序:循环计数2500次结束循环,返回主程序
(2)编写键盘中断程序思路:
利用栈存储寄存器数据,然后判断键盘状态,通过读写DSR的方式来显示输入的字符10次,直到输入回车字符,结束循环,恢复寄存器,返回用户程序
2.利用LC-3的汇编代码设计实现相关程序
点击LC3Edit.exe,根据实验设计思路在LC-3Edit里编写汇编代码
(1)编写用户程序:
A、首先将栈指针初始化为x3000,将键盘中断调用号x0180的内容更换为x2000,即自己重新编写的中断服务程序的起始地址,最后
将x4000赋给KBSR,将KBSR的IE位置1,支持中断
B、打印第一行:调用子程序DELAY进行延时,循环输出6次第一行的“ICS ”,直至键盘输入,启动中断服务程序
C、打印第二行:调用子程序DELAY进行延时,循环输出5次第二行的“ICS ”,直至键盘输入,启动中断服务程序
D、编写子程序DELAY:通过循环计数,每次从2500递减到0,计数完成,然后返回主程序
E、编写数据区:
(2)编写键盘中断服务程序:
A、将用户程序的寄存器全部存入栈中,每次栈指针R6地址减一,指向最新的地址,分别储存R0,R1,R2,R3
B、判断键盘状态Ready位为1时,判断当前输入字符是否为回车符,通过将回车符的ASCII码的负值-x0A赋给R3,与当前输入的字符即R0的内容相加判断输入的字符是不是回车字符,如果是的话结束中断服务程序,返回用户程序;如果不是回车符,显示键盘输入的字符10次,具体代码如下:
C、中断服务程序的数据区以及寄存器的恢复:通过栈区的push操作依次恢复R3,R2,R1,R0,通过RTI返回用户程序
3.通过LC-3仿真器调试和运行相关程序并得到正确的结果
(1)打开simulate.exe,导入上述的.obj文件,进行运行和调试
(2)运行程序:点击运行程序run program键,运行结果如下:
(3)键盘未输入字符时,运行如下:
(4)键盘输入依次字符“123”时,未按回车符时,运行如下:
(5)按了回车符后,返回用户程序,运行结果如下:
(6)调试程序:
(a)单击,停止程序
(b)重新点击运行程序run program键,更改键盘输入值,多次输入字符,在不同位置中断,运行结果正确,具体如下:
四、实验结论:
1.整体上较好的完成本次实验目的,完成了本次键盘中断实验的设计和运行,使用键盘作为输入来中断正在运行的程序。
2.通过本次实验,我更加熟悉地掌握了LC-3Edit和simulate的使用方法,也对于LC-3的中断机制的理解更为深刻。
3.通过本次实验,懂得通过利用计数循环的DELAY子程序实现延时的效果,还有对于栈区数据的存储和提取操作,以及栈区的LIFO原则更为了解。另外,通过本次实验,还掌握了将KBSR的IE位置1来支持中断等操作,通过修改中断调用号内容为自己编写的中断服务程序的起始地址的方法来实现中断服务。
4.总体来说,本次实验我加深了对LC-3中断服务程序的理解和掌握程度,明白了真正动手实践解决问题,才能够深入理解和掌知识点,真的受益匪浅。
五、汇编代码(仅供参考)
汇编代码的思路:根据上面实验思路进行设计,具代码参见注释
(一)用户程序源代码:
;此程序功能:
;使用键盘作为输入来中断正在运行的程序
;
;
;用户程序
.ORIG x3000
;初始化栈指针为x3000
LD R6,Stack ;initialize the stack pointer(栈指针初始化为x3000)
;重新设置键盘中断
LD R1,Entry ;Set up the keyboard interrupt table entry.设置键盘中断号x0180
LD R2,Start ;将中断程序的开始地址传给R2(R2<-x2000)
STR R2,R1,#0 ;修改中断号x0180内容,中断开始时将跳转到x2000处执行中断程序
;启用中断程序
LD R3,IE ;将x4000赋给R3
STI R3,KBSR ;将KBSR的IE位置1,支持中断enable keyboard interrupts
;打印第一行ICS
Begin AND R4,R4,#0 ;
ADD R4,R4,#6 ;
Print1 BRz Del1 ;
LEA R0,ICS1 ;将ICS1的首地址给R0,便与输出
PUTS ;调用系统函数输出第一个字符串
JSR DELAY ;调用延时DELAY子程序,使得键盘输出内容能够看清
ADD R4,R4,#-1 ;
BRnzp Print1 ;
Del1 LD R0,chanline ;换行
OUT ;
JSR DELAY ;调用延时DELAY子程序,使得键盘输出内容能够看清
;打印第二行ICS
AND R4,R4,#0 ;
ADD R4,R4,#5 ;
Print2 BRz Del2 ;
LEA R0,ICS2 ;将ICS2的首地址给R0,便与输出
PUTS ;调用系统函数输出第二个字符串
JSR DELAY ;调用延时DELAY子程序,使得键盘输出内容能够看清
ADD R4,R4,#-1 ;
BRnzp Print2 ;
Del2 LD R0,chanline ;换行
OUT ;
JSR DELAY ;调用延时DELAY子程序,使得键盘输出内容能够看清
BRnzp Begin ;
Halt ;
;DELAY 子程序:通过计数2500次来实现延时输出
DELAY ST R1,SaveR1 ;保存R1
LD R1,COUNT ;R1<-#2500
LOOP ADD R1,R1,#-1 ;
BRp LOOP ;如果R1为正,一直返回LOOP继续循环,直到为0,结束循环
LD R1,SaveR1 ;恢复R1
RET
Stack .fill x3000
Entry .fill x0180 ;键盘中断调用号
Start .fill x2000
IE .fill x4000
KBSR .fill xFE00 ;键盘状态寄存器
ICS1 .STRINGZ "ICS "
ICS2 .STRINGZ " ICS"
chanline .fill x000A
COUNT .FILL #25000
SaveR1 .FILL #0
.END
(二)中断服务程序源代码:
;键盘中断服务程序:实现功能:输出键盘输入的字符10次
;
;将用户程序的寄存器全部存入栈中
.ORIG X2000
ADD R6,R6,#-1 ;栈指针指向栈区最后一个地址,将用户程序的寄存器数据存入栈中
STR R0,R6,#0 ;将当前正要输出的字符串ICS的首地址即R0存入栈中
ADD R6,R6,#-1 ;
STR R1,R6,#0 ;将R1内容(x0180)存入栈中:
ADD R6,R6,#-1 ;
STR R2,R6,#0 ;将R2内容(x2000)存入栈中:
ADD R6,R6,#-1 ;
STR R3,R6,#0 ;将R3(x4000)内容存入栈中:
;判断键盘状态,并输出
Check LDI R1,KBSR ;
BRzp Check ;判断输入状态寄存器KBSR的Ready位,不是1,键盘无输入,为1时说明键盘有输入,跳出循环
LDI R0,KBDR ;键盘有输入时,将输入的数据即KBDR内容存入R0
SaR0 ST R0,SaveR0 ;保存R0,便于循环10次内容不变
LD R3,End ;将-x0A赋给R3
ADD R3,R3,R0 ;
BRz Save ;如果不是回车就继续循环输入,并输出当前字符10次,直到输入回车结束整个循环
AND R2,R2,#0 ;
ADD R2,R2,#10 ;R2作为循环计数器,置为10
Again LD R0,SaveR0 ;恢复R0
Out2 LDI R1,DSR ;
BRzp Out2 ;判断显示状态寄存器DSR的Ready位,为1时说明空闲,可以输出下一个字符
STI R0,DDR ;将DDR内容输出
ADD R2,R2,#-1 ;
BRp Again ;
BRnzp Check ;回到验证键盘是否输入
Save LDR R3,R6,#0 ;恢复R3
ADD R6,R6,#1 ;以LIFO原则恢复寄存器内容
LDR R2,R6,#0 ;恢复R2
ADD R6,R6,#1 ;
LDR R1,R6,#0 ;恢复R1
ADD R6,R6,#1 ;
LDR R0,R6,#0 ;恢复R0
ADD R6,R6,#1 ;
RTI
;
SaveR0 .fill #0 ;
End .fill XFFF6 ;回车ASCII码的相反数
KBSR .fill xFE00 ;键盘状态寄存器
KBDR .fill xFE02 ;键盘数据寄存器
DSR .fill xFE04 ;显示状态寄存器
DDR .fill xFE06 ;显示数据寄存器
.END