第15节:外中断
CPU在计算机系统中,除了能够执行指令运算外,
还应该对外部设备进行控制,接受它们的输入,向它们进行输出。
I/O需解决2个问题:
1.外设的输入随时可能发生,CPU如何得知?
2.CPU从何处得到外设的输入?
1.接口芯片和端口:
外设的输入不直接送入内存和CPU,而是送入相关的接口芯片和芯片的端口中。
CPU向外设的输出也不是直接接入外设,而是先送入端口中,再由相关的芯片送到外设。
CPU<–>端口<–>外设
2.外中断信息:
外设的输入随时可能发生,CPU如何得知并进行处理?—>中断机制
外中断源分类:
a.可屏蔽中断
CPU可以不响应的外中断。CPU是否响应可屏蔽中断,要看标志寄存器IF位的设置。
当CPU检测到可屏蔽中断信息时,如果IF=1,则CPU在执行完当前指令后响应中断,引发中断过程。
IF=0,则不响应可屏蔽中断。
1.标志寄存器入栈,IF=0,TF=0;
2.CS,IP入栈
3.(IP)=(n*4),(CS)=(n*4+2)
将IF置0的原因就是,在进入中断处理程序后,禁止其他的可屏蔽中断。
if在中断处理程序中需要处理可屏蔽中断,可以用指令将IF置1。8086CPU提供的指令是:
sti,设置IF=1
cli,设置IF=0
b.不可屏蔽中断
CPU必须响应的外中断。当CPU检测到不可屏蔽中断信息时,则在执行完当前指令后,立即响应,引发中断过程。
8086中不可屏蔽中断类型码固定为2,所以中断过程,不需要取中断类型码
1.标志寄存器入栈,IF=0,TF=0;
2.CS,IP入栈
3.(IP)=(8),(CS)=(0AH)
(几乎所有由外设引发的外中断,都是可屏蔽中断。)
3.PC机键盘的处理过程:
a.键盘输入:
键盘键(开关)——>按下键(通码)——>产生扫描码(松开的键在键盘的位置)——>松开(断码)——>产生的扫描码也送入60h端口中
扫描码长度为1个字节,通码的第7位为0,断码的第7位为1
断码=通码+80h
eg:g键的通码为22h,断码为a2h
b.引发9号中断:
到达60h端口——>芯片向CPU发出中断类型码为9的可屏蔽中断信息——>IF=1,则响应中断——>转去执行int9中断例程
c.执行int9中断例程:
BIOS提供了int9中断例程,用来进行基本的键盘输入处理
1.读出60h端口中的扫描码
2.字符键扫描码——>扫描码和对应的ASCII送入BIOS键盘缓冲区
控制键(ctrl..)和切换键(Capslock..)扫描码——>状态字节写入内存中存储状态字节单元
3.对键盘系统进行相关的控制,eg向相关芯片发出应答信息
BIOS键盘缓冲区是系统启动后,BIOS用于存放int 9中断例程所接收的键盘输入的内存区。
该内存区可以存储15个键盘输入,一个键盘输入用一个字单元存放,高位字节存放扫描码,低位字节存放字符码。
0040:17单元存储键盘状态字节,
该字节记录了控制键和切换键的状态。键盘状态字节各位信息的如下:
0: 右shift状态,置1表示按下右shift键;
1: 左shift状态,置1表示按下左shift键;
2: Ctrl状态,置1表示按下ctrl键;
3: Alt状态,置1表示按下alt键;
4: Scrollock状态,置1表示scroll指示灯亮;
5: NumLock状态,置1表示小键盘输入的是数字;
6: CapsLock状态,置1表示输入大写字母;
7: Insert状态,置1表示处于删除状态;
4.编写int 9中断例程:
键盘输入的处理过程:
a.键盘产生扫描码
b.扫描码送入60h端口
c.引发9号中断
d.CPU执行int 9中断例程处理键盘输入
a,b,c都是由硬件系统完成的。我们只能改变的只有int 9中断例程处理程序。
编程:在屏幕中间依次显示‘a’~’z’,并可以让人看清。在显示的过程中,按下Esc键后,改变显示的颜色
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
mov ax,0
mov es,ax
push es:[9*4]
pop ds:[0]
push es:[9*4+2]
pop ds:[2] ;将原来int 9中断例程的入口地址保存在ds:0,ds:2单元中
mov word ptr es:[9*4],offset int9
mov es:[9*4+2],cs ;在中断向量表中设置新的int9中断例程的入口地址
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,0
mov es,ax
push ds:[0]
pop es:[9*4]
push ds:[2]
pop es:[9*4+2] ;将中断向量表中int 9中断例程的入口恢复到原来的地址
mov ax,4c00h
int 21h
delay:push ax
push dx
mov dx,1000h
mov ax,0
s1: sub ax,1
sbb dx,0
cmp ax,0
jne s1
cmp dx,0
jne s1
pop dx
pop ax
ret
;-----------以下为新的int 9中断例程----------------
int9: push ax
push bx
push es
in al,60h
pushf
pushf
pop bx
add bh,11111100b
push bx
popf
call dword ptr ds:[0] ;对int指令进行模拟,调用原来的int 9中断例程
cmp al,1
jne int9ret
mov ax,0b800h
mov es,ax
inc byte ptr es:[160*12+40*2+1] ;将属性值加1,改变颜色
int9ret:pop es
pop bx
pop ax
iret
code ends
end start
5.安装新的int 9中断例程:
任务:安装一个新的int9中断例程
功能:在dos下,按f1键后改变当前屏幕的显示颜色,其他的键照常处理
1.改变屏幕的显示颜色:
2.其他键照常处理
3.原int9中断例程入口地址的保存
4.新int9中断例程安装
将int9中断例程安装在0:204处
assume cs:code
stack segment
db 128 dup(0)
stack ends
code segment
start: mov ax,stack
mov ss,ax
mov sp,128
push cs
pop ds
mov ax,0
mov es,ax
mov si,offset int9
mov di,204h
mov cx,offset int9end-offset int9
cld
rep movsb
push es:[9*4]
pop es:[200h]
push es:[9*4+2]
pop es:[202h]
cli
mov word ptr es:[9*4],204h
mov word ptr es:[9*4+2],0
sti
mov ax,4c00h
int 21h
int9: push ax
push bx
push cx
push es
in al,60h
pushf
call dword ptr cs:[200h]
cmp al,3bh
jne int9ret
mov ax,0b800h
mov es,ax
mov bx,1
mov cx,2000
s: inc byte ptr es:[bx]
add bx,2
loop s
int9ret:pop es
pop cx
pop bx
pop ax
iret
int9end:nop
code ends
end start
指令系统总结:
1.数据传送指令
mov push pop pushf popf xchg //实现寄存器和内存,寄存器和寄存器之间的单个数据传送
2.算术运算指令
add sub adc sbb inc dec cmp imul idiv aaa//实现寄存器和内存中数据的算数运算。
执行结果影响标志寄存器sf,zf,of,cf,pf,af位
3.逻辑指令
and or not xor test shl shr sal rol ror rcl rcr //除了not指令外,执行结果都影响标志寄存器的相关标志位
4.转移指令
jmp jcxz je jb ja jnb jna loop call ret retf int iret
5.处理机控制指令
cld std cli sti nop clc cmc stc hlt wait esc lock//指令对标志寄存器或其他处理机状态进行设置
6.串处理指令
movsb movsw cmps scas lods stos //对内存中批量数据进行处理,若要使用这些指令方便进行批量数据的处理,则需要和rep repe repne等前缀指令配合使用