端口的读写
对端口的读写不能用mov、push、pop等内存读写指令。
端口的读写指令只有两条:in和out,分别用于从端口读取数据和往端口写入数据。
访问内存:mov ax,ds:[8];假设执行前(ds)=0
执行时,与总线相关的操作:
① CPU通过地址线将地址信息8发出;
② CPU通过控制线发出内存读命令,选中存储器芯片,并通知它,将要从中读取数据;
③ 存储器将 8号单元中的数据通过数据线送入CPU。
访问端口:in al,60h;从60h号端口读入一个字节
执行时与总线相关的操作:
① CPU通过地址线将地址信息60h发出;
② CPU通过控制线发出端口读命令,选中端口所在的芯片,并通知它,将要从中读取数据;
③ 端口所在的芯片将60h端口中的数据通过数据线送入CPU。
注意:在in和out 指令中,只能使用 ax 或al 来存放从端口中读入的数据或要发送到端口中的数据。访问8 位端口时用 al ,访问16 位端口时用ax 。
对0~255以内的端口进行读写:
- in al,20h ;从20h端口读入一个字节
- out 20h,al ;往20h端口写入一个字节
对256~65535的端口进行读写时,端口号放在dx中:
- mov dx,3f8h ;将端口号3f8送入dx
- in al,dx ;从3f8h端口读入一个字节
- out dx,al ;向3f8h端口写入一个字节
shl和shr指令
shl逻辑左移指令,功能为:
(1)将一个寄存器或内存单元中的数据(二进制类型)向左移位;
(2)将最后移出的一位写入CF中;
(3)最低位用0补充。
指令:mov al,01001000b
shl al,1 ;将al中的数据左移一位
执行后(al)=10010000b,CF=0。
如果移动位数大于1时,必须将移动位数放在cl中。
比如,指令:
mov al,01010001b
mov cl,3
shl al,cl
执行后(al)=10001000b,因为最后移出一位是0,所以CF=0。
将X逻辑左移一位,相当于执行X=X*2。
shr逻辑右移指令
它和shl所进行的操作刚好相反:
(1)将一个寄存器或内存单元中的数据向右移位;
(2)将最后移出的一位写入CF中;
(3)最高位用0补充。
编程:在屏幕中间显示当前的月份。
分析:这个程序主要做两部分工作:
(1)从CMOS RAM的8号单元读出当前月份的BCD码;要读取 CMOS RAM的信息,我们首先要向地址端口70h写入要访问的单元的地址:
mov al,8
out 70h,al
然后从数据端口71h中取得指定单元中的数据:in al,71h
(2)将用BCD码表示的月份以十进制的形式显示到屏幕上。
我们可以看出 ,BCD 码值=十进制数码值,则BCD码值+30h=十进制数对应的ASCII码。
从CMOS RAM的8号单元读出的一个字节中,包含了用两个 BCD 码表示的两位十进制数,高4位的 BCD码表示十位,低 4位的 BCD码表示个位。比如:00010100b表示14。
1 assume cs:code 2 code segment 3 start:mov al,8 4 out 70h,al ; 从地址端口70h,写入要访问的内存单元的地址 5 in al,71h ; 从数据端口71h,获取第8号内存单元(月)的数据 6 mov ah,al ; 将月的值赋给ah 7 8 mov cl,4 ; 右移4次 9 shr ah,cl ; 获取月份十位数的值(因为要把每一位数+30h) 10 and al,0000 1111b ; 获取月份十位数的值 11 12 add ah,30h 13 add al,30h ; BCD码 ==> ASCII码 14 15 mov bx,0b800H ; 定位到显存的位置 16 mov ds,bx ; 我也不知道要写啥 17 mov byte ptr ds:[160*12+40*2],ah 18 mov byte ptr ds:[160*12+40*2+2],al 19 20 mov ax,4c00h 21 int 21h 22 code ends 23 end start