端口和外中断
各种存储器都和CPU的的地址线、数据线、控制线相连。CPU在操作它们的时候,把它们都当作内存来看代,把它们总地看作一个由若干存储单元组成地逻辑存储器,这个逻辑存储器我们称其位内存地址空间。
在PC机系统中,和CPU通过总线相连地芯片除各种存储器外,还有以下3种芯片。
- 各种接口卡(比如,网卡、显卡)上的接口芯片,它们控制接口卡进行工作;
- 主板上的接口芯片,CPU通过它们对部分外设进行访问;
- 其它芯片,用来存储相关的系统信息,或进行相关的输入输出处理。
在这些芯片种,都有一组可以由CPU读写的寄存器。这些寄存器,它们在物理上可能处于不同的芯片种,但是它们在以下两点上相同。
- 都和CPU的总线相连,当然这种连接是通过它们所在的芯片进行的;
- CPU对它们进行读或写的时候都通过控制线向它们所在的芯片发出端口读写命令。
可见,从CPU的角度,将这些寄存器都当作短裤,对他们进行统一编址,从而建立了一个统一的端口地址空间。每一个端口在地址空间种都有一个地址。
CPU可以直接读写以下3个地方的数据。
- CPU内部的寄存器;
- 内存单元;
- 端口。
1. 端口的读写
在PC系统种,CPU最多可以定位64KB个不同的端口。则端口地址的范围为0~65535。
对端口的读写不能用mov、push、pop等内存读写指令。端口的读写指令只有两条;in和out,分别用于从端口读取数据和往端口写入数据。
访问端口:
in al, 60H
执行时与总线相关的操作如下。
- CPU通过地址线将地址信息60H发出;
- CPU通过控制线发出端口读命令,选中端口所在的芯片,并通知它,将要从中读取数据;
- 端口所在的芯片将60H端口中的数据通过数据线送入CPU。
注意:在in和out指令中,只能使用ax或al来存放从端口读入的数据或要发送到端口中的数据。访问8位端口时用al,访问16位端口用ax。
对0~255以内的端口进行读写时:
in al, 20H
out 20H, al
对256~65535的端口进行读写时,端口号放在dx中:
mov dx, 3f8H
in al, dx
out dx, al
2. CMOS RAM芯片
PC机中,有一个CMOS RAM芯片,特征如下:
-
包含一个实时钟和一个有128个存储单元的RAM存储器;
-
该芯片靠电池供电。所以,关机后其内部的实时钟仍可正常工作,RAM中的信息不丢失。
-
128个字节的RAM中,内部实时钟占用0~0dH单元来保存时间信息,其余大部分单元用于保存系统配置信息,供系统启动时BIOS程序读取。BIOS也提供了相关的程序,使我们可以在开机的时候配置CMOS RAM中的系统信息。
-
该芯片有两个端口,端口地址为70H和71H。CPU通过这两个端口来读写CMOS RAM。
-
70h为地址端口,存放要访问的CMOS RAM单元的地址;71H为数据端口,存放从选定的CMOS RAM单元中读取的数据,或要写入到其中的数据。可见,CPU对CMOS RAM的读写分两步进行,比如,读CMOS RAM的2号单元:
1. 将2送入端口70H端口; 2. 从端口71H读出2号单元的内容。以下编程实现读取CMOS RAM的2号单元的内容和向CMOS RAM的2号单元写入0。
assume cs:code code segment start: mov al, 2 out 70H, al in al, 71H mov ax, 4c00H int 21H code ends end startassume cs:code code segment start: mov al, 2 out 70H, al mov al, 0 out 71H, al mov ax, 4c00H int 21H code ends end start
3. shl和shr指令
shl和shr是逻辑移位指令,不管是左移还是右移都是补0。
它们的功能是:
- 将一个寄存器或内存单元中的数据向左/右移位;
- 将最后一个移出的一位写入CF中;
- 低位/高位用0补充。
mov al, 01001000B
shl al, 1 ;将al中的数据左移一位
如果移动位数大于1时,必须将移动位数放在cl中。
mov al, 01010001B
mov cl, 3
shl al, cl
编程,用加法和移位指令计算(ax) = (ax)x10。
assume cs:code
code segment
start: mov ax, 1
shl ax, 1 ;左移一位相当于乘2
mov bx, ax ;保存(ax)*2
mov cl, 2
shl ax, cl ;共左移3位相当于乘8
add ax, bx
mov ax, 4c00H
int 21
code ends
end start
4. CMOS RAM中存储的时间信息
在CMOS RAM中,存放着当前的时间:年、月、日、时、分、秒。这6个信息的长度都为1个字节,存放单元为:
秒:0 分:2 时:4 日:7 月:8 年:9
这些数据以BCD码的形式存在。
编程:在屏幕中间显示当前的月份。
分析:这个程序主要做以下两部分工作。
- 从CMOS RAM的8号单元读出当前月份的BCD码
- 将用BCD码表示的月份以十进制的形式显示到屏幕上。
BCD码值 = 十进制数码值, 则BCD码值 + 30H = 十进制数对应的ASCII码。
assume cs:code
code segment
start: mov al, 8
out 70H, al
in al, 71H
mov ah, al
mov cl, 4
shr ah, cl ;右移四位,获得BCD码十位上的数
and al, 00001111B ;获得BCD码个位上的数字
add ah, 30H
add al, 30H
mov bx, 0b800H
mov es, bx
mov byte ptr es:[160*12+40*2], ah
mov byte ptr es:[160*12+40*2+2], al
mov ax, 4c00H
int 21H
code ends
end start
实验14 访问CMOS RAM
5. 外中断
我们知道,CPU在计算机系统中,除了能够执行指令,进行运算以外,还应该能够对外部设备进行控制,接收它们的输入,向他们进行输出。也就是说,CPU除了有运算能力外,还要有I/O能力。
5. 1 接口芯片和端口
外设的输入不直接送入内存和CPU,而是送入相关的接口芯片的端口中;CPU向外设的输入也不是直接送入外设,而是送入端口中,再由相关的芯片送到外设。CPU还可以向外设输出控制命令,而这些控制命令也是先送到相关芯片的的端口中,然后再由相关的芯片根据命令对外设实施控制。
可见,CPU通过端口和外部设备进行联系。
6. 外中断信息
我们知道了外设的输入被存放在端口中,可是外设的输入随时都有可能到达,CPU如何及时地知道,并进行处理呢?
CPU提供中断机制来满足这种需要。当CPU外部有需要处理的事情发生的时候,比如说,外设的输入到达,相关芯片将向CPU发出相应的中断信息。CPU在执行完当前指令后,可以检测到发送过来的中断信息,引发中断过程,处理外设的输入。
在PC系统中,外中断源一共有以下两类。
6.1 可屏蔽中断
可屏蔽中断是CPU可以不响应的外中断。CPU是否响应可屏蔽中断,要看标志寄存器IF位的设置。当CPU检测到可屏蔽中断信息时,如果IF=1,则CPU在执行完当前指令后响应中断;如果IF=0,则不响应可屏蔽中断。
我们回忆一下内中断所引发的中断过程:
- 取中断类型码n;
- 标志寄存器入栈,IF=0,TF=0;
- CS、IP入栈;
- (IP)=(nx4),(CS)=(nx4+2)
几乎所有由外设引发的外中断,都是可屏蔽中断。
可屏蔽中断所引发的中断过程,在第一步上实现有所不同,其他步骤基本上和内中断的中断过程相同。因为可屏蔽中断信息来自于CPU外部,中断类型码是通过数据总线送入CPU的;而内中断的中断类型码是在CPU内部产生的。
当然,如果在中断处理程序中需要处理可屏蔽中断,可以用指令将IF置为1。8086CPU提供的设置IF的指令如下:
sti, 设置IF = 1;
cli, 设置IF = 0
6.2 不可屏蔽中断
不可屏蔽中断是CPU必须响应的外中断。当CPU检测到不可屏蔽中断信息时,则在执行完当前指令后,立即响应,引发中断过程。
对于8086CPU,不可屏蔽中断的中断类型码固定为2,所以中断过程中,不需要取中断类型码。则不可屏蔽中断的中断过程为:
- 标志寄存器入栈,IF = 0,TF=0;
- CS、IP入栈;
- (IP)=(8),(CS)=(0AH)。