2022年自陷程序和子程序 .pdf
《2022年自陷程序和子程序 .pdf》由会员分享,可在线阅读,更多相关《2022年自陷程序和子程序 .pdf(14页珍藏版)》请在得力文库 - 分享文档赚钱的网站上搜索。
1、第九章自陷程序和子程序9.1 LC-3 自陷程序9.1.1 介绍回忆先前一章的图8.5 的程序,为了成功地获得从键盘输入,程序员需要知道以下几件事情(第8 章) :1、键盘与显示器的硬件数据寄存器:显示器的数据寄存器是为了能够显示一个提示符,而键盘数据寄存器则是让程序知道到哪儿去寻找输入的字符。2、键盘与显示器的硬件状态寄存器:显示器的状态寄存器是为了让程序知道什么时候可以显示提示符中的下一个字符,而键盘状态寄存器则让程序知道什么时候有人键入了一个字符。3、键盘输入和执行程序之间的异步关系。这是大多数应用程序员不知道的知识。实际上,在现实中,如果应用程序员(或有时称为“用户程序员” )必须在这
2、个层面上理解输入与输出,那么在商业上将会很少运用输入/输出,程序员也会大大减少。另外,如果允许用户程序员直接访问KBDR 和 KBSR 等来实现输入/输出的行为,将会造成另外一个问题出现。输入/输出行为包含了被许多程序所共享的设备寄存器的使用,这就意味着,如果一个用户程序员被允许访问硬件寄存器,他/她没有谨慎处理,这会给其他用户程序制造混乱。这样, 让用户程序员访问这些寄存器是不明智的。我们说硬件寄存器是有特权的,那些不拥有适当特权级别的程序是不能访问它们的。特权的概念带来了一大堆麻烦。不幸的是, 我们在这里不能做更多的涉及,把它留给以后做更认真的处理。现在, 我们只是注意到这里有用户程序不能
3、访问的资源,只有那些被赋予足够特权的程序才可以控制它们,而没有特权的程序则不可以。说完这些, 我们继续手头上的问题,如何“更好”的解决需要输入和/或输出的用户程序。一个更简单同时也是更安全的解决需要I/O 的用户程序问题的方案包括自陷(TRAP)指令和操作系统。操作系统拥有适当的特权级别。我们已经在第5 章介绍了TRAP 指令。我们看到,在某些任务中,用户程序通过调用TRAP 指令使操作系统做这个工作。这样,用户程序不必要知道前面提到的复杂的细节,并且其他用户程序也会被保护起来,避免用户程序员的不恰当行为的后果。图 9.1 显示了一个用户程序在到达地址x4000 时,需要执行一个输入输出任务。
4、用户程序请求操作系统代表它完成这个任务。操作系统控制机器,处理 TRAP 指令指定的请求,然后把控制权返还给用户程序。我们经常把这个用户程序的请求称为服务调用或系统调用。9.1.2 TRAP 机制TRAP 机制包括一些要素,如下:1、 一组由操作系统代表用户程序去执行的服务程序。它们是操作系统的一部分,在存储器中的起始地址是任意的。LC-3 被设计为总共可以识别256 个服务程序。附录A 中的表名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 1 页,共 14 页 - - - - -
5、- - - - A.2 包含了 LC-3 现有的操作系统服务程序的完整列表。2、这 256 个服务程序的起始地址的一张表。这张表被存储在存储单元的x0000 到 x00FF中。不同的公司对这张表有不同的命名,一家公司叫它系统控制块,另一家公司叫它Trap向量表。图9.2 提供了一个LC-3 的 Trap 向量表的瞬态图。在这些起始地址中,字符输出服务程序(单元x0430)包含在单元x0021 中;键盘输入服务程序(单元x04A0 )包含在单元x0023 中,还有,停机服务程序(单元xFD70)包含在单元x0025 中。3、TRAP 指令。当用户程序希望让操作系统代表用户程序执行某一个服务程序,
6、然后把控制权交还给用户程序时,用户程序使用TRAP 指令。4、返回用户程序的一个链接。服务程序必须有一种可以把控制权交还给用户程序的机制。9.1.3 TRAP 指令TRAP 指令通过做两件事实现服务程序的执行:它根据它的trap 向量,改变PC 的值为相应的服务程序的首地址。它提供了一个返回调用TRAP 指令的程序的路径。这个返回路径指的是链接。TRAP 指令说明如下。 TRAP 指令由两部分组成:TRAP 的操作码 1111和 trap 向量(7:0位) 。11:8 位必须为0。trap 向量标识了用户程序希望操作系统执行的程序。在下面的例子中, trap 向量是 x23。15 14 13
7、12 11 10 9 8 7 6 5 4 3 2 1 0 1 1 1 1 0 0 0 0 0 0 1 0 0 0 1 1 TRAP TRAP 向量在 TRAP 指令的指令周期的执行阶段,做4 件事:1、8 位的 trap 向量通过零扩展到16 位而形成一个地址,该地址被加载到MAR 。对于trap 向量 x23,地址就是x0023,它是 TRAP 向量表中的一条记录的地址;2、TRAP 向量表位于存储单元x0000 到 x00FF 中。位于 x0023 中的纪录被读取,它的内容是 x04A0(如图 9.2) ,被加载到MDR 中;3、通用寄存器R7 被加载为PC 中的当前内容。这会给用户程序提
8、供一个返回路径,这一点马上就会变得更清楚;4、MDR 的内容被加载到PC 中,完成这个指令周期。由于 PC 现在包含了x04A0 ,所以处理从存储单元x04A0 继续下去。地址 x04A0 是从键盘输入一个字符的操作系统服务程序的起始地址。我们说trap 向量指向 TRAP 程序的起始地址。因此,TRAP x23 使操作系统开始执行键盘输入服务程序。为了返回到位于用户程序中的TRAP 指令之后的指令(在执行完服务程序之后),必须有一个机制保存用户程序的下一条指令的地址。在上面列出的执行阶段的第3 步提供了这个链接。 在把服务程序的起始地址加载到PC 之前,通过在R7 中保存 PC 的值, TR
9、AP 指令为服务程序提供了将控制返回到用户程序的适当单元的全部信息。你知道,PC 已经被更新 (在TRAP 指令的取指令阶段) ,指向下一条指令。这样,TRAP 服务程序开始执行,R7 包含了紧跟在 TRAP 指令之后的用户程序指令的地址。9.1.4 完整的机制我们已经详细的显示了TRAP 指令如何调用服务程序来实现程序的命令,我们也显示了名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 2 页,共 14 页 - - - - - - - - - TRAP 指令如何提供服务程序需要的将控
10、制返回到用户程序的正确位置的信息。剩下的唯一的事就是显示将控制返回到用户程序的正确位置的服务程序中的真正的指令。回忆第 5 章的JMP 指令。假设在TRAP 服务程序执行的过程中,R7 的内容未被改变。如果是那样的话,通过在 TRAP 服务程序的最后执行一条JMP R7 指令,控制就可以返回到用户程序的正确位置。图 9.3 显示了 LC-3 使用 TRAP 和 JMP 指令来完成图9.1 的例子。控制流从一个需要从键盘输入字符的用户程序开始(A) ,到代表用户程序执行此任务的操作系统服务程序(B) ,再返回到可能会使用在输入字符中包含的信息的用户程序(C) 。回忆计算机继续执行指令周期(取指令
11、,译码等),正如你所知道的,改变控制流的方式就是在当前指令的执行阶段,改变PC 中的内容。这样,下一次取指令阶段读取的将是改变了方向的地址。因此,要调用字符输入服务程序,我们调用使用了trap 向量 x23 的 TRAP 指令。该指令的执行使存储单元x0023 的内容(在这个例子里包含了x04A0 )被加载进PC,同时紧跟在 TRAP 指令之后的指令地址被加载到R7 中。图 9.3 中的虚线显示了使用trap 向量从 trap向量表中获得TRAP 服务程序的起始地址。下一个指令周期从取得x04A0 的内容开始,也就是请求(接受)键盘输入的操作系统服务程序的第一条指令。我们马上就看到的那段服务程
12、序,跟我们在8.4 节中学过的键盘输入程序是一样的。回忆那一段完整的输入程序(图8.5) ,R0 包含了那个键入的键的ASCII码。TRAP 服务程序以JMP R7 指令结束。 JMP R7 指令的执行,将PC 加载为 R7 的内容。如果 R7 在执行服务程序期间没有改变,它将会包含原始的用户程序中紧跟着TRAP 指令之后的那条指令的地址。因此,用户程序继续执行,且R0 包含了从键盘输入的字符的ASCII码。JMP R7 指令对于返回用户程序提供了如此的便利,以至 LC-3 汇编程序为这条指令提供了一个助记符RET ,如下所示:15 14 13 12 11 10 9 8 7 6 5 4 3 2
13、 1 0 1 1 0 0 0 0 0 1 1 1 0 0 0 0 0 0 RET 下面的程序被用来说明TRAP 指令的使用。它也可以被用来逗一个4 岁的孩子玩!例 9.1 写一个做如下事情的游戏程序:一个人坐在键盘前,每次这个人键入一个大写字符,程序输出该字符的小写。如果此人键入了一个7,程序结束。下面的 LC-3 汇编程序作了该工作。 01 .ORIG x3000 02 LD R2, TERM ; 加载 -7 03 LD R3,ASC; 加载 ASCII 码的差值 04 AGAIN TRAP x23 ; 请求键盘输入 05 ADD R1, R2, R0 ; 测试是否是终止字符 06 BRz
14、EXIT 07 ADD R0, R0, R3 ; 改变为小写字母 08 TRAP x21 ; 输出到显示器 09 BRnzp AGAIN ; 再做一次 0A TERM .FILL xFFC9 ; xFFC9 是 7 的 ASCII 码的负数 0B ASC .FILL x0020 名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 3 页,共 14 页 - - - - - - - - - 0C EXIT TRAP x25 ; 停机0D .END 程序执行如下。 首先它分别将xFFC9 和
15、x0020 读入 R2 和 R3。 常数 xFFC9 是 7 的 ASCII码的负数,它是用来测试键盘上输入的字符,看这个四岁的孩子是否想继续玩。常数x0020是一个大写字母与其小写表示的ASCII 码之间的差的零扩展。例如,A 的 ASCII 码是 x41而 a 的 ASCII 码是 x61。Z 和 z 的 ASCII 码分别是x5A 和 x7A 。然后执行 TRAP x23 ,它调用键盘输入服务程序。当服务程序结束,控制返回应用程序(在 05 行)时, R0 包含了键入字符的ASCII 码。 ADD 和 BRz 指令来测试是否是终止字符7。如果键入的字符不是7,大小写的ASCII 码的差(
16、 x0020)将被加到键入字符的ASCII码上,并将结果保存到R0。然后调用显示器输出服务程序,这使得同一字母的小写被显示到屏幕上。当控制返回应用程序(这次在09 行)时,将执行无条件分支转移到AGAIN ,请求另一个键盘输入。在这个例子中,程序的正确运行是假设坐在键盘前的人只输入大写字母和7。但如果他输入“ $”呢?例子9.1 的一个更好的解决方案是能够测试输入的字符,确定它是否是字母表中 26 个字母的大写形式,如果不是,则采取适当的操作。问题: 将测试错误数据增加到上面的程序中。也就是说, 写一段可以将键入的任意大写字母以小写表示,并且如果输入字符不是大写字母,则终止执行的程序(习题9.
17、6) 。9.1.5 处理 I/O 的 TRAP 程序利用上面提供的概念,图 8.5 描述的输入程序可以做稍微修改,成为图 9.4 的输入程序。需要两处改变: (1)我们添加了 .ORIG 和.END 伪操作。 .ORIG 说明了输入服务程序的起始地址 在 trap 向量表的地址x0023 中发现的地址, (2)我们使用JMP R7(助记符 RET)结束这个输入服务程序,而不是使用图8.5 的 20 行的 BR NEXT_TASK 。因为这个服务程序通过 trap x23 调用,所以使用JMP R7。这不是用户程序的一部分,与图8.5 的情况相同。8.3.2 节的输出程序可被做类似的修改,如图
18、9.5 所示。结果就是使用恰当的TRAP 向量的 TRAP 指令,可以简单、安全的调用输入(图9.4)和输出(图9.5)服务程序。在输入的情况下,在完成TRAP x23 后, R0 中包含了从键盘输入的字符的ASCII 码。在输出的情况下,初始程序必须将要想在显示器上显示的字符的ASCII 码加载入R0,然后再调用TRAP x21。9.1.6 停机的 TRAP 程序回想一下,在4.5 节中,运行锁通过与石英振荡器做“与”操作,产生用来控制计算机运行的时种。我们注意到如果那个1 位的锁被清空,那么与门的输出就是0,这样就停止了时钟。多年前,大多数的ISA 都有一条HALT 指令来停止时钟。已知此
19、命令被执行的频率非常低,看起来为它提供一个操作码很浪费。在很多现代计算机中,运行锁的清空是用TRAP程序来实现的。在LC-3 中,运行锁是机器控制寄存器的15位,机器控制寄存器被存储映射到单元xFFFE。图 9.6 显示了停止处理器的TRAP 服务程序,也就是停止时钟的程序。首先( 02,03 和 04 行) ,寄存器 R7、R1 和 R0 都被保存。 R0 和 R1 被保存是因为它们在服务程序中要被用到,R7 被保存是因为它的内容会在执行TRAP x21 (09 行)后被覆盖。然后( 08 行到 0D 行) ,“Halting the machine”(停止机器)这个标识被显示在显示器上。最
20、后( 11 行到 14 行) ,运行锁( MCR15 )通过对MCR 与 0111111111111111做“与”操作而名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 4 页,共 14 页 - - - - - - - - - 被清空。 也就是说 MCR14:0 保持不变, 但是 MCR15 被清空。 问题:什么指令 (或是 TRAP服务程序)可以使时钟开始?01 .ORIG xFD70 ; 程序的位置02 ST R7, SaveR7 03 ST R1, SaveR1 ; R1:临时存
21、储MCR 的值04 ST R0, SaveR0 ; R0 用作工作空间05 ; 06 ; 输出停机的消息07 ; 08 LD R0,ASCIINewLine 09 TRAP x21 0A LEA R0, Message 0B TRAP x22 0C LD R0,ASCIINewLline 0D TRAP x21 0E ; 0F ; 清空 xFFFE 的 15 位,停机10 ; 11 LDI R1, MCR ; 加载 MCR 的值到 R1 中12 LD R0,MASK ; R0=x7FFF 13 AND R0, R1, R0 ; 用屏蔽清空最高位14 STI R0, MCR ; 将 R0 的值存
22、储到MCR 中15 ; 16 ;从 HALT 程序返回17 ; 18 ; 19 LD R1,SaveR1 ;恢复寄存器1A LD R0, SaveR0 1B LD R7, SaveR7 1C RET 1D ; 1E ; 一些常数1F ; 20 ASCIINewLine .FILL x000A 21 SaveR0 .BLKW 1 22 SaveR1 .BLKW 1 23 SaveR7 .BLKW 1 24 Message .STRINGZ Halting the machine. 25 MCR .FILL xFFFE ; MCR 的地址26 MASK .FILL x7FFF ; 清空最高位的屏蔽
23、27 .END 图 9.6 LC-3 的停机服务程序名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 5 页,共 14 页 - - - - - - - - - 9.1.7 寄存器的保存和恢复我们应该更加明确强调的我们曾经在过去提到的一点,就是需要保存寄存器中的值,1、 如果该值将被某个接下来的行为破坏,并且2、 如果当完成那个接下来的行为后,我们还需要用到那个值。假设我们想从键盘输入十个十进制数字,将它们的ASCII码转化成二进制表示,并且将这十个二进制数存进以地址“Binary ”开
24、头的十个连续的存储单元。下面的程序片段做个这个工作。01 LEA R3,Binary ;初始化为第一个单元02 LD R6,ASCII ;05 行用到的模板03 LD R7,COUNT ;初始化为10 04 AGAIN TRAP x23 ;获取键盘输入05 ADD R0,R0,R6 ;去掉 ASCII 码模板06 STR R0,R3,#0 ;存储二进制数07 ADD R3,R3,#1 ;指针加1 08 ADD R7,R7,#-1 ;计数器减1 09 BRp AGAIN ;还有更多字符?0A BRnzp NEXT_TASK ;0B ASCII .FILL xFFD0 ;x0030 的负数0C C
25、OUNT .FILL #10 0D Binary .BLKW #10 这个程序片段的第一步是初始化。我们用为存储这10 个十进制数而分配的存储器空间的起始地址来加载R3。我们将 ASCII 码模板的负数加载R6,这是为了从每一个ASCII 码减去 x0030。我们把计数器的初始值10 存入 R7。然后执行十次循环,每次从键盘上取一个字符,去除ASCII 码模板,储存二进制结果,并检验我们是否做完。但是这段程序不能运行!为什么?答案:04 行的 TRAP 指令将 03 行里加载到R7 的值“ 10”替换为ADD R0,R0,R6指令的地址。所以08 和 09 行的指令没有执行被安排做的循环控制功
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 2022年自陷程序和子程序 2022 程序 子程序
限制150内