汇编入门笔记(十三)

0x41:端口简介

在PC机系统中,和CPU通过总线相连的芯片除各种存储器外,还有以下3种芯片。

  • 各种接口卡(比如,网卡、显卡)上的接口芯片,它们控制接口卡进行工作;
  • 主板上的接口芯片,CPU通过它们对部分外设进行访问;
  • 其他芯片,用来存储相关的系统信息,或进行相关的输入输出处理。

在这些芯片中,都有一组可以由CPU读写的寄存器。这些寄存器,它们在物理上可能处于不同的芯片中,
但是它们在以下两点上相同。

  • 都和CPU的总线相连,这种连接是通过它们所在的芯片进行的;
  • CPU对它们进行读或写的时候都通过控制线向它们所在的芯片发出端口读写命令。

从CPU的角度,将这些寄存器都当作端口,对它们进行统一编址,从而建立了一个统一的端口地址空间
每一个端口在地址空间中都有一个地址。在访问端口的时候,CPU通过端口地址来定位端口。因为端口所在的芯片和CPU通过总线相连。

CPU可以直接读写以下3个地方的数据:

  • CPU内部的寄存器;
  • 内存单元;
  • 端口。

0x42:端口的读写

端口地址和内存地址一样,通过地址总线来传送。在PC系统中,CPU最多可以定位64KB个不同的端口。则端口地址的范围为0-65535

端口的读写指令只有两条:inout,分别用于从端口读取数据和往端口写入数据。

注意:只能使用ax或al来存放从端口读入或写入端口的数据,分别对应8位、16位端口。

在in和out指令中,只能使用ax或al来存放从端口中读入的数据或要发送到端口中的数据。

1
2
3
4
5
6
7
8
;对0~255以内的端口进行读写时:
in al, 20h ;从20h端口读入一个字节
out 20h, al ;往20h端口写入一个字节

;对256~65535的端口进行读写时,端口号放在dx中:
mov dx, 3f8h ;将端口号3f8h送入dx
in al, dx ;从3f8h端口读入一个字节
out dx, al ;向3f8h端口写入一个字节

0x43:shl和shr指令

shl和shr是逻辑移位指令

shl是逻辑左移指令,它的功能为:

  1. 将一个寄存器或内存单元中的数据向左移位;
  2. 将最后移出的一位写入CF中;
  3. 最低位用0补充。

shr是逻辑右移指令,同理:

1
2
3
4
5
6
7
8
9
mov al, 01001000b 
shl al, 1 ;将a1中的数据左移一位执行后(al)=10010000b,CF=0。

mov al, 01010001b
mov cl, 3 ;如果移动位数大于1时,必须将移动位数放在cl中
shl al, c1

mov al, 10000001b
shr al, 1 ;将al中的数据右移一位执行后(al)=01000000b,CF=1。

0x44:外中断

CPU在计算机系统中,除了能够执行指令,进行运算以外,还应该能够对外部设备进行控制,接收它们的输入,向它们进行输出(I/O能力)。

两个问题:1.外设的输入可能随时发生,CPU如何得知?2.CPU从何得到外设的输入?

外设的输入不直接送入内存和CPU,而是送入相关的接口芯片的端口中;
CPU向外设的输出也不是直接送入外设,而是先送入端口中,再由相关的芯片送到外设。

即:CPU通过端口和外部设备进行联系。

当CPU外部有需要处理的事情发生的时候,比如说,外设的输入到达,相关芯片将向CPU发出相应的中断信息。CPU在执行完当前指令后,可以检测到发送过来的中断信息,引发中断过程,处理外设的输入。

PC系统中,外中断源有两类

1、可屏蔽中断

可屏蔽中断是CPU可以不响应的外中断。CPU是否响应可屏蔽中断,要看标志寄存器的IF位的设置。
当CPU检测到可屏蔽中断信息时,如果IF=1,则CPU在执行完当前指令后响应中断,引发中断过程;如果IF=0,则不响应可屏蔽中断。

可屏蔽中断信息来自于CPU外部,中断类型码是通过数据总线送入CPU的;而内中断的中断类型码是在CPU内部产生的。

中断过程中将IF置0的原因就是,在进入中断处理程序后,禁止其他的可屏蔽中断。

如果在中断处理程序中需要处理可屏蔽中断,可以用指令将IF置1。

8086CPU提供的设置IF的指令:sti,设置IF=1;cli,设置IF=0。

2、不可屏蔽中断

不可屏蔽中断是CPU必须响应的外中断。当CPU检测到不可屏蔽中断信息时,则在执行完当前指令后,立即响应,引发中断过程。

对于8086CPU,不可屏蔽中断的中断类型码固定为2,所以中断过程中,不需要取中断类型码。则不可屏蔽中断的中断过程为:①标志寄存器入栈,IF=0,TF=0;②CS、IP入栈;③(IP)=(8),(CS)=(0AH)。

几乎所有由外设引发的外中断,都是可屏蔽中断。当外设有需要处理的事件(比如说键盘输入)发生时,相关芯片向CPU发出可屏蔽中断信息。不可屏蔽中断是在系统中有必须处理的紧急情况发生时用来通知CPU的中断信息。

CPU对外设输入的通常处理方法:
(1)外设的输入送入端口;
(2)向CPU发出外中断(可屏蔽中断)信息;
(3)CPU检测到可屏蔽中断信息,如果IF=1,CPU在执行完当前指令后响应中断,执行相应的中断例程;
(4)可在中断例程中实现对外设输入的处理。

端口和中断机制,是CPU进行I/O的基础。

0x45:直接定址表

先来看一段程序:

将code段中的a标号处的8个数据累加,结果存储到b标号出的字中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
assume cs:code
code segment
a : db 1,2,3,4,5,6,7,8 ;在后面加有“:”的地址标号,只能在代码段中使用,不能在其他段中使用。
b : dw 0
start :mov si,offset a
mov bx,offset b
mov cx,8
s : mov al,cs:[si]
mov ah,0
add cs:[bx],ax
inc si
loop s
mov ax,4c00h
int 21h
code ends
end start

注意:在后面加有“:”的地址标号,只能在代码段中使用,不能在其他段中使用!

程序中,code、a、b、start、s都是标号。这些标号仅仅表示了内存单元的地址。

但是我们还可以使用一种标号,它不仅可以表示内存单元的地址,还可以表示内存单元的长度,字节单元、字单元或者双字单元。

下面程序中的标号描述了单位长度:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
assume cs:code
code segment
a db 1,2,3,4,5,6,7,8 ;标号a、b后面没有":",因此它们是可以同时描述内存地址和单元长度的标号。
;标号a,描述了地址code:0,和从这个地址开始,以后的内存单元都是字节单元
b dw 0 ;标号b描述了地址code:8,和从这个地址开始,以后的内存单元都是字单元。
start : mov si,0
mov cx,8
s : mov al,a[si]
mov ah,0
add b,ax
inc si
loop s
mov ax,4c00h
int 21h
code ends
end start

image-20210930104305089

image-20210930104405959

使用数据标号来描述存储数据的单元的地址和长度。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
assume cs:code,ds:data ;用伪指令assume将标号所在的段和一个段寄存器联系起来(编译器需要)
data segment
a db 1,2,3,4,5,6,7,8
b dw 0
data ends
code segment
start: mov ax,data
mov ds,ax ;真正确定ds寄存器
mov si,0
mov cx,8
s: mov al,a[si] ;编译为:mov al,[si+0] 默认所访问单元的段地址在ds
mov ah,0
add b,ax ;编译为:add [8],ax
inc si
loop s
mov ax,4c00h
int 21h
code ends
end start

汇编入门系列正式完结。

坚持原创技术分享,您的支持将鼓励我继续创作!