第十五章 外中断
体现了cpu的I/O能力。
1)cpu如何得知外设输入了?
2)cpu如何得到外设的输入?
15.1 接口芯片和端口
cpu通过端口和外部设备进行联系
15.2 外中断信息
外部设备通过外中断来通知cpu 引发中断过程,处理外设的输入。
外中断源:
1. 可屏蔽中断
可屏蔽中断是cpu可以不响应的外中断。 例如IF =1 则cpu会响应可屏蔽中断,如果IF=0 cpu则不响应
内中断引发的中断过程:
1)取中断类型码n;
2)标志寄存器入栈, IF=0, TF=0
3) CS,IP入栈
4)(IP)=(n*4), (CS) = (n*4 + 2)
如果需要接受可屏蔽外部中断设置IF =1
sti; if = 1
cli; if = 0
(std; df = 1
cld; df = 0)
2. 不可屏蔽中断
在8086中,不可屏蔽中断固定为2.,不需要取中断类型码
1) 标志寄存器入栈,IF=0, TF=0
2) CS, IP入栈
3)(IP) = (8), (CS) = (0AH)
15.3 PC机键盘的处理过程
1. 键盘输入
按下和松开按键产生扫描码
存放在端口60h
按键产生通码;松开一个键产生断码。扫描码长度为1个字节,通码第七位是0 ,断码第七位是1
断码 = 通码 + 80h
2. 引发9号中断
有键盘输入,除了在端口60h存放相应的扫描码,还会向cpu发送INT 9 中断。
3. 执行int 9 中断的例程
BIOS中有中断9的例程,用来进行基本的键盘输入处理。
15.4 编写int 9 中断例程
1)键盘产生扫描码
2)扫描码送入60h端口
3)引发9号中断
4)cpu执行int9中断例程处理键盘输入。
编程:在屏幕依次显示 a~z ,并且可以让人看清。在显示过程中,按下ESC键后,改变现实颜色。
运行代码如下
assume cs:code stack segment db 128 dup (0) stack ends code segment start: mov ax, stack mov ss, ax mov sp, 128 mov ax, 0b800h mov es, ax mov ah, 'a' s: mov es:[160*12 + 40*2], ah call delay inc ah cmp ah, 'z' jna s mov ax, 4c00h int 21h delay: pushf push ax push dx mov dx, 2000h ; loop for 10,000,000h times mov ax, 0 nextd: sub ax, 1 sbb dx, 0 cmp ax, 0 jne nextd cmp dx, 0 jne nextd pop dx pop ax popf ret code ends end start接下来要编写装载int9点程序
1. 从端口60h读入键盘输入
2 调用bios的int9 中断例程
模拟中断例程的过程
假设事先将INT9的入口地址放在ds:0 和ds:2
1)标志寄存器入栈
2)IF=0,TF=0 屏蔽外部中断和单步调试中断
3)CS, IP入栈
4)(IP)=((16)*16 + 0), (cs) = (16*(ds) + 2)
pushf
pushf
pop ax
and ah, 1111 1100b
push ax
popf
call dword ptr ds:[0]
3.
assume cs:code stack segment db 128 dup (0) stack ends data segment dw 0, 0 data ends code segment start: mov ax, stack mov ss, ax mov sp, 128 mov ax, data mov ds, ax ; store the original int9 entry address of system mov ax, 0 mov es, ax push es:[9 * 4] pop ds:[0] push es:[9 * 4 + 2] pop ds:[2] ; set the new irq procedure for int9 mov word ptr es:[9*4], offset int9 mov es:[9 * 4 + 2], cs mov ax, 0b800h mov es, ax mov ah, 'a' s: mov es:[160 * 12 + 40 * 2], ah call delay inc ah cmp ah, 'z' jna s ; restore the entry address for int9 of system. mov ax, 0 mov es, ax push ds:[0] pop es:[9 * 4] push ds:[2] pop es:[9 * 4 + 2] mov ax, 4c00h int 21h ; delay sub procedure delay: pushf push ax push dx mov dx, 1000h ; loop for 10,000,000h times mov ax, 0 nextd: sub ax, 1 sbb dx, 0 cmp ax, 0 jne nextd cmp dx, 0 jne nextd pop dx pop ax popf ret ; sub procedure for int9 int9: push ax push bx push es in al, 60h pushf pushf pop bx and bh, 11111100b push bx popf call dword ptr ds:[0] ;call the original int9 procedure of System cmp al, 1 ; use has press the esc . 1 is the scan code for ESC jne int9ret mov ax, 0b800h mov es, ax inc byte ptr es:[160 * 12 + 40 * 2 +1] ; change color int9ret: pop es pop bx pop ax iret code ends end start
运行结果:
增加了安全机制在设置INT9向量地址的时候防止相应了外部中断而导致程序运行错误。
assume cs:code stack segment db 128 dup (0) stack ends data segment dw 0, 0 data ends code segment start: mov ax, stack mov ss, ax mov sp, 128 mov ax, data mov ds, ax ; store the original int9 entry address of system mov ax, 0 mov es, ax push es:[9 * 4] pop ds:[0] push es:[9 * 4 + 2] pop ds:[2] ; set the new irq procedure for int9 cli ; ignore the outside irq mov word ptr es:[9*4], offset int9 mov es:[9 * 4 + 2], cs sti ; restore the IF flag. mov ax, 0b800h mov es, ax mov ah, 'a' s: mov es:[160 * 12 + 40 * 2], ah call delay inc ah cmp ah, 'z' jna s ; restore the entry address for int9 of system. mov ax, 0 mov es, ax cli ; ignore the outside irq push ds:[0] pop es:[9 * 4] push ds:[2] pop es:[9 * 4 + 2] sti ; restore the IF flag. mov ax, 4c00h int 21h ; delay sub procedure delay: pushf push ax push dx mov dx, 1000h ; loop for 10,000,000h times mov ax, 0 nextd: sub ax, 1 sbb dx, 0 cmp ax, 0 jne nextd cmp dx, 0 jne nextd pop dx pop ax popf ret ; sub procedure for int9 int9: push ax push es in al, 60h pushf call dword ptr ds:[0] ;call the original int9 procedure of System cmp al, 1 ; use has press the esc . 1 is the scan code for ESC jne int9ret mov ax, 0b800h mov es, ax inc byte ptr es:[160 * 12 + 40 * 2 +1] ; change color int9ret: pop es pop ax iret code ends end start
15.5 安装新的int9 中断例程
任务:安装一个新的int9 中断例程
功能:在DOS下,按F1键后改变当前屏幕的显示颜色,其他按键照常处理。
assume cs:code stack segment db 128 dup (0) stack ends code segment start: mov ax, stack mov ss, ax mov sp, 128 ; set es:di as target address 0000:0200h mov ax, 0 mov es, ax mov di, 204h ; set ds:si as source address cs:sqr mov ax, cs mov ds, ax mov si, offset int9 ; set cx as the data length mov cx, offset int9end - offset int9 ; set the transport directive DF = 0 cld cld rep movsb ; store the original entry cs:ip of int9 to 0:200 push es:[9 * 4] pop es:[200h] push es:[9 * 4 + 2] pop es:[202h] ; set the IRQ table 1F0 = 200h(IP) 1F2 = 0(CS) mov ax, 0 mov es, ax cli ; ignore the outside irq mov word ptr es:[9 * 4], 204h mov word ptr es:[9 * 4 + 2], 0 sti ; restore the outside irq. mov ax, 4c00h int 21h ; sub procedure for int9 int9: push ax push bx push cx push es in al, 60h pushf call dword ptr cs:[200h] ;call the original int9 procedure of System cmp al, 3bh ; scan code for F1 jne int9ret mov ax, 0b800h mov es, ax mov bx, 1 mov cx, 2000 int9s: inc byte ptr es:[bx] ; change color add bx, 2 loop int9s int9ret: pop es pop cx pop bx pop ax iret int9end: nop code ends end start
运行结果
实验15 安装新的int9 中断例程
功能:在dos下,按下F2键,除非不再松开,如果松开,显示满屏幕的 A。 (原书的例子是A键,但是这会影响正常的输入)
assume cs:code stack segment db 128 dup (0) stack ends code segment start: mov ax, stack mov ss, ax mov sp, 128 ; set es:di as target address 0000:0200h mov ax, 0 mov es, ax mov di, 204h ; set ds:si as source address cs:sqr mov ax, cs mov ds, ax mov si, offset int9 ; set cx as the data length mov cx, offset int9end - offset int9 ; set the transport directive DF = 0 cld cld rep movsb ; store the original entry cs:ip of int9 to 0:200 push es:[9 * 4] pop es:[200h] push es:[9 * 4 + 2] pop es:[202h] ; set the IRQ table 1F0 = 200h(IP) 1F2 = 0(CS) mov ax, 0 mov es, ax cli ; ignore the outside irq mov word ptr es:[9 * 4], 204h mov word ptr es:[9 * 4 + 2], 0 sti ; restore the outside irq. mov ax, 4c00h int 21h ; sub procedure for int9 int9: push ax push bx push cx push es in al, 60h pushf call dword ptr cs:[200h] ;call the original int9 procedure of System cmp al, 0bch ; scan code for release F2 jne int9ret mov ax, 0b800h mov es, ax mov bx, 0 mov cx, 2000 mov al, 'A' int9s: mov es:[bx], al ; ptint A add bx, 2 loop int9s int9ret: pop es pop cx pop bx pop ax iret int9end: nop code ends end start运行结果