790 likes | 890 Views
微型计算机技术. 学习辅导( 4 ). 太原广播电视大学 郭建勇. 第四章 汇编语言程序设计基础 4 . 1 循环程序设计 在程序设计中,常常需要一段程序反复执行若干次,这通常用循环的方法来实现,借助几种循环控制指令和前缀可以方便地实现循环。 4 . 1 . 1 基本结构的循环程序 (1) 初始化部分:循环前的准备工作,包括建立指针、设置变量及循环初值等。 (2) 循环体:这是循环程序的工作部分,完成循环的基本操作。 (3) 修改部分:修改参数,包括操作数地址、循环计数值或其他控制变量。 (4) 控制部分:根据对循环条件的判断结果,控制循环的执行或结束。.
E N D
微型计算机技术 学习辅导(4) 太原广播电视大学 郭建勇
第四章 汇编语言程序设计基础 • 4.1循环程序设计 • 在程序设计中,常常需要一段程序反复执行若干次,这通常用循环的方法来实现,借助几种循环控制指令和前缀可以方便地实现循环。 • 4.1.1基本结构的循环程序 • (1)初始化部分:循环前的准备工作,包括建立指针、设置变量及循环初值等。 • (2)循环体:这是循环程序的工作部分,完成循环的基本操作。 • (3)修改部分:修改参数,包括操作数地址、循环计数值或其他控制变量。 • (4)控制部分:根据对循环条件的判断结果,控制循环的执行或结束。 初始化 初始化 先工作后判断 先判断后工作 Y 循环控制 循环体 N 循环体 修改部分 Y 修改部分 循环控制 N
开始 CX←循环记数值 • 例:编制一个程序,将BX寄存器中的二进制数用十六进制数的形式显示出来。 • (1) BX寄存器中的二进制数可用 • 4位十六进制数显示,故循环次数为 • 4,放入CH中。 • (2) BX循环左移4次,最高位数字 • 移到最低位置; • (3)0~9的数字与ASCII码差为30H; • A~F(41H ~46H)与ASCII码差为 • 37H;故0~9的数字+30H,而A~F • 应+37H。 BX循环左移4次 转换为ASCII码 >9? +7 显示 次数=0? 结束
PROGNAM SEGMENT MOV AH,4CH • MAIN PROC FAR INT 21H • ASSUME CS:PROGNAM MAIN ENDP • START: MOV CH ,4 PROGNAM ENDS ROTATE: MOV CL ,4 • ROL BX ,CL • MOV AL , BL • AND AL ,0FH • ADD AL ,30H • CMP AL ,3AH • JL PIRNTIT • ADD AL ,07H PIRNTIT:MOV DL ,AL MOV AH ,4CH INT 21H DEC CH JNZ ROTATE
例:统计某字单元中二进制数位值为1的个数,统计结果存放在变量ONE中。例:统计某字单元中二进制数位值为1的个数,统计结果存放在变量ONE中。 • DATA SEGMENT • NUM DW 1669H FINI: MOV AH,4CH • ONE DB ? INT 21H • DATA ENDS CODE ENDS • CODE SEGMENT END START • ASSNUM CS:CODE • DS:DATA • START:MOV AX ,DATA • MOV DS,AX • MOV AX,NUM • COMP:CMP AX,0 • JZ FINI • SHL AX,1 • JNC COMP • INC ONE • JMP COMP 开始 AX←NUM AX=0? Y AX左移一位 结束 CF=1? Y ONE+1
4.1.2 多重循环程序 • 一个计算过程可能要依赖几个互相独立变化的参数,这就需要在一个循环过程中再包含一个循环过程,形成外层循环嵌套内层循环的结构形式,这种程序就称为多重循环程序。 • 多重循环程序设计的基本方法和单重循环程序设计是一致的,应分别考虑各层循环的控制条件及其程序实现,相互之间不能混淆。另外要注意在每次通过外层循环再次进入内层循环时,初始条件必须重新设置。 • 例:有一个首地址为A的N字数组,请编制程序使该数组中的数按照从小到大 的次序排列(整序)。 • 采用起泡排序算法实现整序:从第一个数开始依次对相邻两个数Ki和Ki十l进行比较,若Ki ≤ Ki十l , Ki的位置不动, Ki十l继续和Ki十2比较;若Ki > Ki十1,则两者交换位置。 Ki十1(交换前的Ki)继续和Ki十2比较。 • 可以看出,在第一遍比较了N-1次后,最大的数已经放到了最后,所以在第二遍时,只需比较N-2次,同样道理,第三遍只需比较n-3次…。如果有N个数,最多要比较n-1遍。
序号 数 比较遍数 • 1 2 3 4 • 比较次数 • 1 2 3 4 1 2 3 1 2 1 • 1 32 32 32 16 16 15 15 8 8 • 2 85 85 16 16 32 15 15 16 8 8 15 15 • 3 16 16 85 15 15 15 32 8 8 8 16 1616 • 4 15 15 85 8 8 8 32 323232 • 5 8 8 85 85 85 85 85 • 第一遍 比较5-1=4次 挑出最大数 85 • 第二遍 比较5-2=3次 挑出第二大数 32 • 第三遍 比较5-3=2次 挑出第三大数 16 • 第四遍 比较5-4=1次 挑出第四大数 15 完成整序
开始 置外循环次数 N-1 置内循环次数 N-1 I=0 N KI≤KI+1? KI←→KI+1 I=I+1 CNUNT2-1 N =0? CNUNT1-1 N =0? 结束
DSEG SEGMENT • N EQU 5 • A DW 5 DUP(?) • DSEG ENDS • CSEG SEGMENT • MAIN PROC FAR • ASSUME CS:CSEG, • DS:DSEG • START:MOV AX ,DSEG • MOV DS ,AX NUM :ADD SI ,2 • MOX CX, N LOOP LOOP2 • DEC CX MOV CX ,DX • LOOP1:MOV DX ,CX LOOP LOOP1 • MOV SI ,0 MOV AH ,4CH • LOOP2:MOV AX ,A[SI] INT 21H • CMP AX ,A[SI+2] MAIN ENDP • JLE NUM XCHG AX,A[SI+2] CSEG ENDS • MOV A[SI],AX END START
4.2 分支程序设计 • 4.2.1 分支程序结构 • 两路(单重)分支结构 多路(多重)分支结构 • 这两种结构都要求先对条件进行判定,然后根据判定结果确定执行哪路分支,判定一次只能有一路分支被选择。一般来讲一个条件两路分支;N个条件,2N路分支。 N 判定条件 判定条件 Y A B A B X
4.2.2 分支程序的设计方法 • 分支程序的实现方法有多种,最常用的方法有:利用比较和条件转移指令实现分支, 利用逻辑尺控制分支,以及利用地址跳转表实现分支等方法。 • 例: X/2 X<0 • Y= 2 X=0 • 2X X>0 这个问题可以通过X与0的比较,利用条件转移指令来确定三个计算分支中的某一支。 • MOV AL ,X • CMP AL ,0 • JL M1 • JZ M2 • SAL AL ,1 • JMP NEXT • M1: SAR AL ,1 • JMP NEXT • M2: MOV AL ,2 • NEXT: MOV X ,AL AL←X Y N X<0? Y N AL÷2 X=0? AL←2 AL×2 X←AL
利用逻辑尺控制分支也是常见的一种分支程序设计方法。例:编写一个显示程序,要求显示A和B共8次,显示次序为A3次,B2次,A1次,B2次。因此,可设计一个逻辑尺:00011011,0表示显示A,1表示显尔B。编程时,逐值测试逻辑尺,是0则执行显示A的分支,是l则执行显示B的分支。部分程序如下:利用逻辑尺控制分支也是常见的一种分支程序设计方法。例:编写一个显示程序,要求显示A和B共8次,显示次序为A3次,B2次,A1次,B2次。因此,可设计一个逻辑尺:00011011,0表示显示A,1表示显尔B。编程时,逐值测试逻辑尺,是0则执行显示A的分支,是l则执行显示B的分支。部分程序如下: • .. .. .. • MOV CX,8 • MOV BL,00011011B • LOP: SHL BL,1 • JC M1 • CALL AA1 • JMP NEXT • M1: CALL BB1 • NEXT: LOOP LOP • HLT CX←次数 BL←逻辑尺 逻辑尺左移一位 =1? N Y 执行B 执行A 分支程序设计时要注意各个 分支一定要转入到公共操作 上。本例和上例中的橙色框。 N CX-1=0?
利用地址跳转表的方法主要用于多路分支(三路分支以上)的情况,下面通过一个实例来说明这种程序设计方法。利用地址跳转表的方法主要用于多路分支(三路分支以上)的情况,下面通过一个实例来说明这种程序设计方法。 • 在调用DOS文件管理功能时,如出现了错误(如使用了非法功能号),DOS • 则根据AX中的错误码,将相应的错误信息显示出来。(AX)=1~5各表示一种错误,其错误信息分别为ERl ~ ER5。AX除l ~ 5之外的数码是无效的。 • (1)错误信息提示的地址 • 分别为ERl ~ ER5。 • (2)ERl ~ ER5构成跳 • 转表,表首地址为ERTAB。 • (3)表中各项的地址为 • 表首址+(功能号-1)×2 ER1 1号错误 提示 ERTAB ER1 ER2 2号错误 提示 ERTAB+2 ER2 ER3 3号错误 提示 ERTAB+4 ER3 ER4 4号错误 提示 ERTAB+6 ER4 ER5 5号错误 提示 ERTAB+8 ER5
DATA SEGMENT CMP AX ,5 • OUTR DB “非1~5$”JG OUTR ;≥5转至OUTR • ER1 DB “错误1提示$”CMP AX ,1 • ER2 DB “错误2提示$”JGE TADR ;1~5转TADR • ER3 DB “错误3提示$”OUTR: LEA DX ,OUTR • ER4 DB “错误1提示$”JMP DISPM ;转至DISPM • ER5 DB “错误1提示$”TADR: MOV BX ,AX • EVEN DEC BX • ERTAB DW ER1,ER2,ER3 SHL BX ,1 • DW ER4,ER5 MOV DX ,ERTAB[BX] • DATA ENDS DISPM: MOV AH ,9 • CODE SEGMENT INT 21H • SHOWERR PROC FAR POP BX ;恢复现场 • ASSUME CS:CODE,DS:DATA POP DX • MOV SI ,DATA POP AX • MOV DS ,SI REG • PHSU AX ;保护现场 SHOWERR ENDP • PUSH DX CODE ENDS • PUSH BX END
4.3 子程序设计 • 子程序又称为过程,在程序实现中,如果要多次用到一些功能相同的程序段,那么就可以用伪操作PROC和ENDP把这些程序段定义成子程序。需要时用CALL指令来调用它,调用程序也称为主程序。 • 子程序有两种属性:NEAR(缺省的属性)和FAR。和调用程序在同一代码段中的子程序使用NEAR属性,和调用程序不在同一代码段中的子程序使用FAR属性。 • 4.3.1 主程序与子程序之间的参数传送 • 主程序在调用子程序时,需要传送一些参数(入口参数)给子程序,子程序运行完后也要将运行结果(出口参数)回送给主程序。 • 利用寄存器传送参数 • 传送参数的方式: 利用存储区传送参数 • 利用堆栈传送参数 • 1.利用寄存器传送参数 • 这种参数传送的方式方便、快速,但只适合传送参数较少的情况。 • 例:编写程序,将一个16位二进制数转换成用ASCII表示的十进制数。 • 这是一个常用的转换子程序,应提供给所有的用户调用。因此,要将该子程序的人口参数和出口参数注释清楚,方便调用。
本例是通过DX和DI寄存器传递参数的。 • DATA SEGMENT • OUTB DB 5 DUP (30H) • N EQU 12345H • DATA ENDS • COND SEGMENT • ASSUME CS:CODE,DS:DATA • START: MOV AX ,DATA • MOV DS ,AX • MOV DX ,N ;入口参数 • LEA SI ,OUTB ;入口参数 • CALL BIN-TO-ASC ;调子程序 • MOV AX,4C00H • INT 21H
入口参数:DX = 被转换数 DI = 结果单元首地址 出口参数: DI = ASCII码结果单元首地址 BIN-TO-ASC PROC PUSH CX ;保护现场 POP DI;恢复现场 PUSH AX POP AX PUSH DI POP CX ADD DI ,4 ;指向最低位 RET BINAO: MOV AX ,DX BIN-TO-ASC ENDP MOV DX ,0 CODE ENDS MOV CX ,10 END START DIV CX ;÷10 XCHG AX ,DX ;商←→余数 ADD AL,30H ;转换ASCII码 MOV [DI],AL ;存结果 DEC DI ;修改指针 CMP DX ,0 JNZ BINA0 ;≠0,转BINA0 本例中,N为二进制数,先除 10,余数为个位,或30H变为 ASCII码;再对商除10,余数 为十位,或30H变为ASCII码; 直至商为0。
2.利用存储区传送参数 • 参数存放在存储区中,入口参数为存储区首地址。适合参数较多的情况。 • 例:TABLE数组中存有15个十进制数,挑出最大数存放在MAX单元中。 • DATA SEGMENT FOUNT PROC • TABLE DB 4,6,8,4,9… MOV AL ,[SI] • N EQU 15 DEC CX • MAX DB ? INC SI • DATA ENDS LOP : CMP AL ,[SI] • CODE SEGMENT JG L1 • ASSUME CS;CODE,DS:DATA MOV AL ,[SI] • START: MOV AX ,DATA L1 : INC SI • MOV DS ,AX LOOP LOP • MOV CX ,N FOUNT ENDP • LEA SI ,TABLE;入口参数 CODE ENDS • CALL FOUNT END START • MOV MAX ,AL • MOV AH ,4CH • INT 21H
3. 利用堆栈传送函数 • 利用堆栈适合于传送参数多,而且子程序有嵌套、递归调用的情况。主程序将参数或参数地址推入堆栈,子程序从堆栈中取出参数或参数地址。利用堆栈传送涵数一定要注意堆栈的变化,如果参数和返回地址混淆,会造成子程序不能正确返回的错误。 • 例:调加密子程序将数组中的数据Aj加密。秘约规则为Aj×2,再各位求反。 • DSEG SEGMENT START: MOV AX ,DSEG • N EQU 20 MOV DS ,AX • ARAY DW N DUP(?) MOV AX ,SSEG • DSEG ENDS MOV SS ,AX • SSEG SEGMENT LEA SP ,TOP ;指定栈底 • DW 64 DUP(?) LEA BX ,ARAY • TOP LABEL WORD PUSH BX ;首地址入栈 • SSEG ENDS MOV BX ,N ;个数入栈 • CSEG SEGMENT PUSH BX • ASSUME CS:CSEG, CALL ECRY • SS:SSEG, MOV AX ,4C00H • DS:DSEG INT 21H
ECRY PROC POP BX • PUSH BP ;用BP取 POP AX • MOV BP ,SP ;入口参数 POP BP • PUSH AX ;保护现场 RET 4 • PUSH BX ECRY ENDP • PUSH CX CSEG ENDS • PUSH SI END START • MOV SI ,0 • MOV CX ,[BP+4];取入口参数 • MOV BX ,[BP+6] • DONE:MOV AX ,[BX+SI] • SHL AX ,1 • XOR AX ,0FFFFH • ADD SI ,2 • LOOP DONE • POP SI ;恢复现场 • POP CX 保护现场后 恢复现场后 SI CX BX AX BP BP SP 返回地址 返回地址 个数N 个数N MOV BP,SP 首地址 首地址 栈底 栈底
4.4 I/O程序设计 • 信息交换 地址端口 : 地址信息 • 主机 I/O接口 数据端口 : 状态信息 • 状态端口 : 数据信息 • 4.4.1 直接控制 I/O的程序设计 • 1.I/O端口 • 在80x86微机中,I/O端口编址在一个独立的地址空间中,这个I/O空间允许设置64K(65536)个8位端口或32K(32768)个16位端口。 • 2.I/O程序举例 • 对于I/O和存储器分离的地址空间系统,80x86有专门的I/O指令与端口进行通信。下面通过几个I/O程序的例子,说明使用I/O指令直接在端口级上输入输出的方法。 • 输入指令 输出指令 • IN AN, 30H OUT 30H ,AL • IN AX, 40H OUT 40H ,AX • IN AL, DX ;DX←16位端口地址 OUT DX ,AX ;DX←16位端口地址 • IN AX, DX ;DX←16位端口地址 OUT DX ,AX ;DX←16位端口地址
例: SOUND程序。 • 程序通过I/O指令使设备控制寄存器(1/O端口地址为61H)的第1位交替为0和l,而61H端口的第l位和扬声器的脉冲门相连,交替为0和l的脉冲电流被放大后送到扬声器使之发出了声音。 • 7 6 5 4 3 2 1 0 • SOUND PROC • PUSH AX • PUSH DX • MOV DX ,1000 • IN AL ,61H DEC DX • AND AL ,11111100B JNZ TRIG TRIG:XOR AL ,00000010B POP DX • OUT 61H ,AL POP AX • MOV CX ,6000 RET • DELAY:LOOP DELAY SOUND ENDP 端口 61H 1/0 与 门 放大器 本例中CX=6000 它决定发声频率 值小声音尖锐, 值大声音低沉。 DX=1000决定 发声时间长短。
例:PRT—CHAR程序。 • 这是一个采用查询方式的打印字符程序。程序通过反复渎取并测试打印机的状态来控制输出。在打印机接口中,数据寄存器的端口地址为378H,状态寄存器的端口地址为379H,控制寄存器的端口地址为37AH。 • 7 6 5 4 3 2 1 0 忙位(0=忙) 未用 • 应答(0=可接受) 打印出错(0=出错) • 纸出界(1=出界) 联机状态(1=联机) • 7 6 5 4 3 2 1 0 • 未用 选通(1=输出数据) • 工作方式 自动换行(1=换行) • (0=禁止中断方式) 初始化(1=正常) • 选择位(1=接通) 状态寄存器 端口379H 控制寄存器 端口37AH
DATA SEGMENT MOV DX,37AH • MESS DB ‘PRINTER IS NORMAL’ MOV AL,0DH ;选通输出 • COUNT EQU $-MESS OUT DX,AL • DATA ENDS MOV AL,0CH • CSEG SEGMENT OUT DX,AL • ASSUME CS:CSEG,DS:DATA INC SI • START:MOV AX,DATA LOOP NEXT • MOV DX,AX MOV AH,4CH • LEA SI,MESS ;建地址指针 INT 21H • MOV CX,COUNT;CX←次数 CSEG ENDS • NEXT: MOV DX,379H ;DX←状态地址 END START • WAIT: IN AL,DX ;AL←状态端口 • TEST AL,80H ;测忙否 • JZ WAIT ;忙(=0)再测 • MOV AL,[SI] ;不忙,输出 • MOV DX,378H ;DX←数据地址 • OUT DX,AL TEST指令测状态寄存器的第7 位,为0表示忙,循环再测, 直至为1空闲时,再取字符输 出打印。称为查询方式。 0DH为控制寄存器选通信号, 0CH为结束选通。
又例:CPU要从3个设备轮流输人数据,PROCl,PROC2,PROC3分别是设备l,设备2和设备3的数据输入程序,它们的状态寄存器的端口地址分别用STAT1,STAT2,STAT3表示,这三个状态寄存器的5位是输入准备位。轮流查询三个数据输入设备的程序段:又例:CPU要从3个设备轮流输人数据,PROCl,PROC2,PROC3分别是设备l,设备2和设备3的数据输入程序,它们的状态寄存器的端口地址分别用STAT1,STAT2,STAT3表示,这三个状态寄存器的5位是输入准备位。轮流查询三个数据输入设备的程序段: • INPUT: IN AL ,STAT1 ;AL←状态寄存器1 • TEST AL ,20H ;输入准备好? • JZ DEV2 ;否,转DEV2 • CALL FAR PTR PROC1 ;准备好,调PROC1 • DEV2: IN AL ,STAT2 • TEST AL ,20H • JZ DEV3 • CALL FAR PTR PROC2 • DEV3: IN AL ,STAT3 • TEST AL ,20H • JZ NO-INPUT • CALL FAR PTR PROC1 • NO-INPUT:…… 查询方式的优点:可以安 排优先次序,最先查询的设 备优先级最高。修改查询次 序就修改了设备的优先级。 缺点:查询等待浪费CPU的 时间,在设备多时由询问转 向处理程序的时间较长。
4.4.2 中断程序设计 中断是一种使CPU中止正在执行的程序而转去处理特殊事件的操作,引起中断的事件称为中断源。 中断是CPU和外部设备进行输入/输出的有效方法。可以避免因反复查询外部设备的状态而浪费时间,从而提高CPU的效率。 中断源分为软件中断(或称内中断)和硬件中断(或称外中断),系统通过分配给这些中断的类型号来加以识别和处理。 80x86中断源及其中断类型号 非屏蔽中断请求 2 NMI 08系统定时器 09键盘 0A彩色/图形 0B串行COM2 0C串行COM1 0D LTP2控制 0E磁盘控制器 0F LTP1控制 IR0 8259A IR1 可编程 IR2 中断 IR3 控制器 IR4 (PIC) IR5 IR6 IR7 INTR CPU 中断逻辑 n 4 0 1 INTn 指令 INT0 指令 除法 错误 单步 TF=1
1.软件中断的执行 • (1)中断指令INT n的执行。 • CPU执行一条INTn指令时,中断系统立即产生类型为n的中断,并且通过中断向量调用相应的中断处理程序来完成其中断功能。 • (2)处理CPU某些错误的中断。 • 除法错中断:在执行除法指令时,若发现除数为0或商超过了寄存器所能表达的范围,则立即产生一个类型为0的中断。 • 溢出中断:有一条专门的指令INTO来中断发生溢出的算术操作。如果OF=1,INTO指令引起中断,如OF:=0,则不发生中断,CPU继续运行原程序。溢出中断的类型号为4。 • (3)为调试程序没置的中断。 • 单步中断:单步是一种很有用的调试方法。当标志位TF设置为l时,每条指令执行后,CPU自动产生类型号为1的单步中断。 • 断点中断:断点可以设置在程序的任何地方,设置断点实际上是把一条断点指令INT3插入程序中,CPU每执行到断点处的INT3指令便产生一个中断。 • INT指令和INTO指令产生的中断。以及除法错中断都不能被禁止,并且比任何外部中断的优先权都高。
2.硬件中断的执行 • 硬件中断:非屏蔽中断(NMI) • 外部设备的请求引起的可屏蔽中断。 • CPU响应中断的条件:该外设的中断请求是否屏蔽:中断屏蔽寄存器(IMR) • CPU是否允许响应中断:标志寄存器中断允许位IF • 中断屏蔽寄存器(IMR)的I/O端口地址是21H。通过设置这个寄存器的某位为0允许中断;为1禁止(屏蔽)中断。 • 中断屏蔽寄存器7 6 5 4 3 2 1 0 • (I/O端口20H) • 打 软 硬 串 串 保 键 定 • 印 行 行 时 • 机 盘 盘 通 通 留 盘 器 • 信 信 • 例:只允许键盘中断,可设置如下中断屏蔽字: • MOV AL ,11111101B ;AL←中断屏蔽字 • OUT 21H ,AL ;送入中断屏蔽寄存器IMR
如果系统增设键蛊中断,则可用下列指令实现:如果系统增设键蛊中断,则可用下列指令实现: • IN AL ,21H ;取中断屏蔽字 • AND AL ,11111101B ;将第1为置0,保留其余位不变 • OUT 21H ,AL ;回送21H端口 • 中断标志位IF的设置: • STI ;设置中断允许位(IF=1),允许中断(开中断) • CLI ;清除中断允许位(1F=0),禁止中断(关中断) • 中断命令寄存器 7 6 5 4 3 2 1 0 • (I/O端口20H) • 中断命令寄存器:EOI是中断结束位,当EOI为1时,当前正在处理的硬件中断请求就被清除,所以在中断处理完成后,必须把中断结束位置为1。 • 结束硬件中断用下面的指令: • MOV AL ,20H ;20H = 00100000B,置EOI为1 • OUT 20H ,AL ; R SL EOI 0 0 L2 L1 L0
INT 4AH 0:124 类型49H 中断向量 MOV CX,30H • 3. 中断操作步骤 • 8086/8088中断系统能处理256种类型的中断,类型号为0~0FFH。中断向量表是各类型中断处理程序的人口地址表。中断向量的地址可由中断类型号乘以4计算出来。 • 以BIOS中断INT 4AH为例, • 表示出中断操作的以下 • 5个步骤: • ①取中断类型号; • ⑦计算中断向量地址; • ③取中断向量,偏移地址 • 送IP,段地址送CS; • ④转人中断处理程序; • ⑤中断返问到INT指令的 • 下一条指令。 ① 向量地址 ③ IP 0:128 05 1805 =4AH×4=128 0:129 18 ② CS 0:12A 00 0:12B F0 F000 类型4BH 中断向量 ④ ⑤ 中断处理程序 F000:1805 STI PUSH DS IRET 采用向量中断可加快 CPU中断处理速度。
0:0000 中断向量表 • 利用保留的中断类型号扩充中断功能,需要在中断向量表中建立相应的中断向量。为中断类型N设置中断向量的方法: • MOV AX ,0 • MOV ES ,AX • MOV BX ,N﹡4 • MOV AX ,OFFSET INHAND • MOV ES :WORD PTR [BX] ,AX • MOV AX ,SEG INHAND • MOV ES :WORD PTR[BX+2] ,AX • INHAND: • IRET (BX)= N﹡4 IP CS ① (BX)+2 ② ② ① OFFSET INHAND INHAND 子程序 IRET SEG INHAND
用自己编写的中断处理程序代替系统中的某个中断处理功能时:用自己编写的中断处理程序代替系统中的某个中断处理功能时: • (1)利用DOS功能调用(21H)保存原中断向量 • (2)设置新的中断向量; • (3)在程序结束之前恢复原中断向量 • 设置中断向量的DOS功能调用 • 把由AL指定的中断类型的中断向量DS:DX放在中断向量表中. • 预置: AH=25H • AL=中断类型号 • DS:DX=中断向量 • 执行:INT 21H • 取中断向量的DOS功能调用 • 把由AL指定的中断类型的中断向量从中断向量表中取到ES:BX中 • 预置:AH = 35H • AL=中断类型号 • 执行:INT 21H • 例:使用DOS功能调用存取中断向量。
利用功能号35H的DOS功能 调用把N类型的中断向量 取到ES:BX中,进行压栈 保存。 • MOV AL ,N ; • MOV AH ,35H ; • INT 21H ; • PUSH ES • PUSH BX • PUSH DS • MOV AX ,SEG INTNAND • MOV DS ,AX • MOV DX ,OFFSET INTHAND • MOV AL ,N • MOV AH ,25H • POP DS 新的中断向量DS:DX利用 功能号25H的DOS功能调用 存入到中断向量表中。中 断类型为N。
将原来压栈保护的中断向量 弹出到DS:DX中,利用功能 号25H的DOS功能调用再存入 到中断向量表中。 • POP DX ; • POP DS ; • MOV AL ,N • MOV AH ,25H • INT 21H • RET • INTHAND: • IRET INTHAND是新的中断服务 子程序的入口符号地址。
1.FKAGS、CS、IP入栈 2.清除IF、TF 3.转中断处理程序 INTHAND 产生中断 • 4.中断过程 • 中断过程: • 1.保存返回地址CS:IP、 • 保存标志寄存器FLAGS。 • 2.CPU还自动清除IF位和 • TF位,目的是使CPU转人中断 • 处理程序后, 不允许再产生 • 新的中断。 • 3.转入中断服务程序。 中断服务 1.IP、CS和FLAGS出栈 2.返回断点,继续执行下一条指令。 IRET 中断返回
5.中断优先级 • 中断优先级: CPU根据中断源的轻重缓急为中断源事先安排的中断优先级次序。 • 当多个中断源同时向CPU请求中断时,CPU先比较它们的优先级,然后从优先级高到优先级低的次序来依次处理各个中断源的中断请求。 • 8086规定中断的优先级次序为: • 优先级高 软件中断(除法错,INTO,INT) • 非屏蔽中断(NMI) • 可屏蔽中断(INTR) • 低 单步中断 • 可屏蔽中断的优先权又分为八级,在正常的优先级方式下,优先级次序是: • 优先级高 低 • IR0,IR1,IR2,IR3,IR4,IR5,IR6,IR7
4.4.3 中断程序设计举例 • 中断处理程序的编写应注意: • (1)中断处理程序若不允许被打断,则清除IF和TF,若允许其他设备中断,则需用STI指令把IF位置1。 • (2)CPU产生一次中断,I/O设备只完成一个字节(或字)的输入/输出,所以中断处理程序所用的指针变量或数据变量一般应设置存储单元来保存。 • (3)硬件设备的中断处理结束后,一般要发出中断结束命令(E0I)。否则将屏蔽同级或低级的中断。 • 例:编写一个中断处理程序,要求在主程序运行过程中,每隔10s响铃一次,同时在屏幕上显示出信息“The bell is ring!”。 • 本例中用新设计的处理程序来代替原有的1CH中断程序,为此: • 在主程序的初始化部分,先保存当前1CH的中断向量,再设置新的中断向量。 • 在主程序的结束部分恢复保存的1CH中断向量。
SCATK1 SEGMENT PARA STACK • DW 100 DUP(?) • STACK1 ENDS • DATA SEGMENT • COUNT DW 1 • MSG DB ‘The bell is ring’,0dh,0ah,’$’ • DATA ENDS • CODE SEGMENT • MAIN PROC FAR • ASSUME CS:CODE,DS:DATA,SS:STACK1 • START: MOV AX ,DATA • MOV DS ,AX • MOV AL ,1CH ;取功能号1CH的中断向量压栈保存 • MOV AH ,35H • INT 21H • PUSH ES • PUSH BX • PUSH DS
MOV DX ,OFFSET RING ;子程序入口地址的偏移量送DX • MOV AX ,SEG RING ;子程序入口地址的段基值送DS • MOV DS ,AX ;中断向量送 DS:DX • MOV AL ,1CH • MOV AH ,25H • INT 21H • POP DS • POP DX • POP DS • STI MOV AL ,1CH • MOV DI ,20000 MOV AH ,25 DELAY:MOV SI ,30000 INT 21H DELAY1:DEC SI MOV AH ,4CH JNZ DELAY1 INT 21H DEC DI MAIN ENDP JNZ DELAY IN 21H AND AL ,11111110B OUT 21H ,AL 设置时钟中断 延时
响 铃 程 序 保护 寄存 器 • RING PROC NEAR SOUNT: XOR AL ,02H • PUSH DS OUT 61H ,AL • PUSH AX MOV CX ,1400H • PUSH CX WAIT1: LOOP WAIT1 • PUSH DX DEC DX • MOV AX ,DATA JNZ SOUNT • MOV DS ,AX MOV COUNT ,182 • STI ;开中断 EXIT: CLI ;关中断 • DEC COUNT MOV AL ,20H • JNZ EXIT OUT 20H ,AL • MOV DX ,OFFSET MSG POP DX • MOV AH ,09H POP CX • INT 21H POP AX • MOV DX ,100 POP DS • IN AL ,61H IRET • AND AL ,0FCH RING ENDP • END START EOI=1清除 中断请求 显示 提示 语 恢复 寄存 器
4.5 BIOS和DOS基本调用 • 在存储器系统中从地址0FE000H开始的8K ROM(只读存储器)中装有BIOS例行程序:系统加电自检、引导装入、主要I/O设备的管理程序以及接口控制等功能模块来处理所有的系统中断。 • 使用BIOS功能调用,给程序员编程带来很大方便。 • DOS提供了一组系统功能调用子程序:包括I/O设备处理程序、文件管理程序和一些其他的处理程序。 • DOS操作比相应功能的BIOS操作更简易,而且对硬件的依赖性更少些。 • BIOS中断类型 • CPU中断类型 • 0 除法错 1 单步 2 非屏蔽中断 3 断点 • 4 溢出 5 打印屏幕 6 保留 7 保留 • 8259中断类型 • 8 系统定时器(IRQ0) C COM1控制器(IRQ4) • 9 键盘(IRQ1) D I‘PT2控制器(IRQ5) • A 彩色/图形接口(IRQ2) E 磁盘控制器(IRQ6) • B COM2控制器(IRQ3) F LPT1控制器(1RQ7)
BIOS中断类型 10 显示器I/O 11 取设备信息 12 取内存容量 13 磁盘I/O 14 RS—232串行口 I/O 15 磁带I/O 16 键盘I/O 17 打印机I/O 18 ROM BASIC 19 引导装入程序 1A 时钟 40 软盘 BIOS • 用户应用程序 • 1B 键盘终止地址(Ctrl-Break) 1C 定时器 • 4A 报警(用户闹钟) • 数据表指针 • 1D 显示器参数表 41 0﹟硬盘参数表 • 1E 软盘参数表 46 1﹟硬盘参数表 • 1F 图形字符扩展码 49 指向键盘增强服务变换表
DOS中断类型 • 20 程序终止 27 结束并驻留内存 • 21 功能调用 28 键盘忙循环 • 22 终止地址 29 快速写字符 • 23 Ctrl-C 中断向量 2A 网络接口 • 24 严重错误向量 2E 执行命令 • 25 绝对磁盘读 2F 多路转接接口 • 26 绝对磁盘写 30~3F 保留给DOS • DOS功能与BIOS功能都通过软件中断调用。 • 基本步骤: • (1)将调用参数装入指定的寄存器中; • (2)如需功能号,把它装入AH; • (3)如需子功能号,把它装入AL; • (4)按中断号调用DOS或BIOS中断; • (5)检查返回参数是否正确。
4.5.1 键盘I/O • 键盘由三种基本类型的键组成: • (1)字符数字键,如字母A(a)一Z(z),数字0—9以及%、$,#等常用字符。 • (2)扩展功能键,如Home,End,Backspace,Arrows,Return,Delete,Insert,PgUp,PgD,以及程序功能键F1一F10等。 • (3)和其他键组合使用的控制键,如A1t,Ctrl和Shift等。 • 字符数字键—ASCII码字符; • 扩展功能键产生一个动作:如按下Home键能把光标移到屏幕的左上角,End键使光标移到屏幕上文本的末尾; • 组合控制键改变其他键所产生的字符码。 • 1.字符码与扫描码 • 键盘上的每个键都对应一个扫描码,根据扫描码就能唯一地确定哪一个键改变了状态。 • 字符码是每个键代表的字符和符号的ASCII码(祥见教材P150页表4.6)
2.BIOS键盘中断 • BIOS键盘中断(INT 16H)的中断处理程序包括3个不同的功能: • AH 功 能 返 回 参 数 • 0 从键盘读一字符 AL=字符码, AH=扫描码 • 1 读键盘缓冲区的字符 如ZF=0,AL=字符码, AH=扫描码 • ZF=1,缓冲区空 • 2 取键盘状态字节 AL=键盘状态字节 • 调用方法: • (1)功能号送入AH • (2)执行 INT 16H 的BIOS中断 • 例如,要查看按键的扫描码和ASCII码,可以调用中断类型16H的0功能。 • MOV AH ,0 ;AH←功能号0, • INT 16H • MOV BX ,AX ;(AX)=(BX)= 扫描码和ASCII码 • CALL BINHEX;调用二进制转换十六进制的子程序
键盘状态字节 KB-FLAG • 键盘上不具有ASCII码的键,如Shift、Ctrl、Alt、Num Lock、Scro11、Ins和Caps lock等,按动了它们能改变其他键所产生的代码。是通过键盘状态字节进行判断按动与否。 • 1=按下右移键R SHIFT • 1=按下左移键L SHIFT • 1=按下控制键CTRL • 1=按下交替键ALT • 1=SCOLL LOCK状态已变 • 1=NUM LOCK状态已变 • 1=CAPS LOCK状态已变 • 1=INSERT状态已变
例:读取键盘状态字节,并以十六进制打印出来。例:读取键盘状态字节,并以十六进制打印出来。 • MOV AH,02H • INT 16H ;BIOS 16H 中断 • MOV BX ,AX ;(AX)=(BX)= 键盘状态字节 • CALL BINIHEX ;转换十六进制打印 • MOV DL ,0DH ;显示CR字符(02号DOS功能调用) • MOV AH ,02H • AGAIN:MOV AH ,02H ;功能号 02H→AH • INT 21H • JMP AGAIN
3.DOS键盘功能调用 • DOS 键盘操作(INT 21H 功能调用) • AH 功 能 调用参数 返回参数 • 1 输入一个字符并显示 AL=字符 • (检测Ctrl-C或Ctrl-break,并调用INT 23H结束程序) • 6 读键盘字符,不回显 DL=0FFH 有字符,AL=字符,ZF=0 • 无字符,AL=0 ,ZF=1 • 7 输入一个字符不显示 AL=字符 • (不支持检测Ctrl-C或Ctrl-break) • 8 输入一个字符不显示 AL=字符 • (检测Ctrl-C或Ctrl-break,并调用INT 23H结束程序) • A 输入字符到缓冲区 DS:DX;缓冲区首址 • B 读键盘状态 AL=0FFH 有键入 • AL=00H 无键入 • C 清除键盘缓冲区 AL=键盘功能号 • 调用一种键盘功能 (1、6、7、8、A)
(1)单字符输入 • 交互程序中常常需要用户对一个提示做出应答,例如,程序显示出一串信息,要求你回答Y或N,回答Y,程序将转入标号为YES的程序段,而回答N使程序转入标号为NO的程序段,按下其他键程序就等待。 • GET-KEY: MOV AH ,1 ;AH←功能号1 • INT 21H • CMP AL ,’Y’;是Y吗? • JE YES ;是Y,转程序YES • CMP AL ,’N’;是N吗? • JE NO ;是N,转程序NO • JNE GET-KEY;等待输入Y或N • 如果想检测Enter(Return)键,就要在指令中写出它的ASCII码0DH,例如: • WAIT-HERE: MOV AH ,7 ;检测键,但不显示或不执行 • INT 21H • CMP AL ,0DH ;是Enter吗?(0DH回车键的ASCII码) • JNE WAIT-HERE
要求程序能接收功能键或数字组合键必须进行两次DOS调用,第一次回送00,第二次回送扫描码。例如,程序显示出一个菜单,要求用户通过键入F1,F2或F3来选择1,2或3项,按其他键则产生错误信息。要求程序能接收功能键或数字组合键必须进行两次DOS调用,第一次回送00,第二次回送扫描码。例如,程序显示出一个菜单,要求用户通过键入F1,F2或F3来选择1,2或3项,按其他键则产生错误信息。 • 例:检测键盘输入的功能键 • MOV AH ,7 • INT 21H ;第一次回送00 • CMP AL ,0 • JE GET-EC ;为0,功能键 • JMP ERROR ;非0,转错误信息 • GET-EC: MOV AH,7 • INT 21H • CMP AL ,3BH ;F1? • JE OPTION1 • CMP AL ,3CH ;F2? • JE OPTION2 • CMP AL ,3DH ;F3? • JE OPTION3 • JMP ERROR ;都不是,转错误信息