r:查看、改变cpu寄存器的内容
d:查看内存中的内容
e:改写内存中的内容
u:将机器码转为汇编语言
t:执行一条语句
a:以汇编指令的格式写入机器指令
g:将使debug从当前cs:ip处开始执行
p:自动执行循环
Debug的T命令在执行修改寄存器ss的指令时,下一条指令也跟着被执行
assume:假设某一段寄存器和程序中的某一个用segment...ends定义的段相关联
可能会出现子程序,可以将子程序和主程序链接成一个程序,
ax,bx,cx,dx;
si,di,sp,bp,ip;
cs,ss,ds,es,psw
指令:
mov 转移指令
jmp 跳转指令
add 加法指令
sub 减法指令
push 入栈
pop 出栈
inc 自增1
and 逻辑与指令,按位进行与运算,通过该操作可以将操作对象的相应位设为0,其他位不变
小写变大写,用and指令将第五位置0,其余都是1
or 逻辑或指令,按位进行或运算,通过该操作可以将操作对象的相应位设为1,其他位不变
大写变小写,用or指令将第五位置1,其余都是0
div 除法指令
jmp 跳转指令 (无条件转移指令) 只修改IP时,称为段内转移,比如:jmp ax
同时修改CS和IP时,称为段间转移,比如:jmp 1000:0(源程序中不可这么写)
由于转移指令对IP的修改范围不同,段内转移又分为:短转移和近转移
·短转移IP的修改范围为-128—127
·近转移IP的修改范围为-32768—32767
jmp 寄存器:只修改IP
jmp 段地址:偏移地址
nop 空指令,什么也不做
jcxz 有条件转移指令
loop 循环指令:所有循环指令都是短转移
dec 自减指令 和inc相反
ret和retf
·ret指令用栈中的数据,修改IP的内容,从而实现近转移
·retf指令用栈中的数据,修改CS和IP的内容,从而实现远转移
call 转移指令,不能实现短转移。实现转移的方法和jmp指令的原理相同
mul 乘法指令
adc 带进位加法指令,利用了CF位上记录的进位值
abb 带借位减法指令,利用了CF位上记录的进位值
cmp 比较指令(compare),相当于减法指令,只是不保存结果
有关cmp的信息
指令 含义 检测的相关标志位
je e:equal 等于则转移 zf=1
jne ne:not equal 不等于则转移 zf=0
jb b:below 低于则转移 cf=1
jnb nb:not blow 不低于则转移 cf=0
ja a:above 高于则转移 cf=0且zf=0
jna na:not above 不高于则转移 cf=1或zf=1
rep 根据cx的值,重复执行后面的串传送指令。由于每执行一次movsb指令si和di都会
递增或者递减指向后一个或前一个单元,则rep movsb就可以循环实现(cx)个字符的传送
rep movsw同理
cld、std 只对df位进行设定的指令(单独使用)
cld 将标志寄存器df位置0,递增
std 将标志寄存器df位置1,递减
pushf和popf:为直接访问标志寄存器提供了一种方法
pushf 将标志寄存器的值压栈
popf 将数据从栈中弹出送入标志寄存器中
iret 返回中断程序
int 引发中断过程
in/out 端口读/写指令,只有这两条
shl和shr 逻辑位移指令
shl 逻辑左移
shr 逻辑右移
sti 设置IF=1
cli 设置IF=0
ax,bx,cx,dx:通用寄存器
可分为高8位和低8位
cs,ds,ss,es:段寄存器
cs和ip:
cs:代码段寄存器
ip:指令指针寄存器
任意时刻,将cs:ip指向的内容当做指令执行
ds和[]:
ds:数据段寄存器
[]:表示一个内存单元。表示一个偏移地址
ss和sp:
ss:存放栈顶的段地址(栈顶寄存器)
sp:存放栈顶偏移地址
任意时刻,ss:sp指向栈顶元素
[bx]和loop:
[bx]和[0]有些类似,表示一个内存单元,它的偏移地址在bx中
约定符号idata表示常量
段前缀:用于显式地指明内存单元的短地址
一段安全的空间:0:200 - 0:2ff这段空间是安全的
dw:define word,定义一个字型数据
db:define byte 定义一个字节型数据
dd:(dword) double word 定义一个双字型数据
dup:和dw、db、dd等数据定义的伪指令配合使用,用来进行数据的重复
比如:db 3 dup (0) 定义了3个字节,它们的值都是0,相当于db 0,0,0
用法:数据定义 重复的次数 dup (重复的数据定义类型数据)
si、di和bx功能差不多,但是不能分割成两个8位的
将计数的内容暂时放到内存中,开辟一段内存空间
reg:表示一个寄存器
sreg:表示一个段寄存器
reg:ax,bx,cx,dx,ah,al,bh,bl,ch,cl,dh,dl,sp,bp,si,di
sreg:ds,ss,cs,es
只要在[]中使用寄存器bp,而没有显性地给出段地址,段地址默认在ss中
bp、bx不能同时出现,si、di也是
SA:段地址
EA:偏移地址
寻址方式:当数据放在内存中的时候,我们可以用多种方式来给定这个内存单元的偏移地址
这种定位内存单元的方法一般称为寻址方式
(汇编语言 表8.2)
直接寻址:[idata],用立即数进行寻址
寄存器间接寻址:[bx]、[bp]、[si]、[di],使用寄存器进行寻址
寄存器相对寻址:[bx+idata]、[bp+idata]、[si+idata]、[di+idata],相对某个值
基址变址寻址:[bx+si]、[bp+si]、[bx+di]、[bx+di],在原有基址的基础上都可以改变,都是变量
相对基址变址寻址:[bx+si+idata]、[bp+si+idata]、[bx+di+idata]、[bx+di+idata],加上相对值
通过寄存器名指明要处理的数据的尺寸
在没有寄存器名存在的情况下,用操作符X ptr指明内存单元的长度,X在汇编指令中可以位word或byte
做除法时应注意下列问题
1、除数:有8位和16位两种,在一个reg或内存单元中
2、被除数:默认放在AX或DX和AX中,如果除数为8位,被除数为16位,
默认放在AX中;如果除数为16位,被除数则为32位,在DX和AX中存放,DX存高16位
AX存低16位
3、结果:如果除数为8位,则AL存商,AH存余数
如果除数为16位,则AX存商,DX存余数
转移指令:可以修改IP,或同时修改CS和IP的指令。
可以控制CPU执行内存中某处代码的指令
转移指令可分为:
·无条件转移指令:jmp
·条件转移指令
·循环指令:loop
·过程
·中断
操作符:offset
·由编译器处理的符号,功能是取得标号的偏移地址
seg
·取得某一标号的段地址
jmp指令要给出两种信息
·转移的目的地址
·转移的距离(段间转移、段内短转移,段内近转移)
段内短转移:jmp short 标号 (转到标号处执行指令)对IP的修改范围为-128-127
CUP在执行jmp指令的时候并不需要转移的目的地址,相对当前IP的转移位移
段内近转移:jmp near ptr (IP)=(IP)+16位位移
段间转移:jmp far ptr 远转移
jmp word ptr 内存单元地址:(段内转移)
·从内存单元地址处开始存放着一个字,是转移的目的偏移地址
jmp dword ptr 内存单元地址:(段间转移)
·从内存单元地址处开始存放着两个字,低地址是转移的目的偏移地址,高地址是段地址
jmp的转移地址可以放在3个地方:
·地址在伪指令中--就是标号(s、s0)
·地址在寄存器中(ax、bx)
·地址在内存中(如上)
内存单元地址可用寻址方式的任何一种格式给出
jcxz指令格式:jcxz 标号(如果cx=0,转移到标号处执行)
如果(cx)不等于0,什么也不做(程序向下执行)
loop指令格式:loop 标号
转移包含的信息是目的地址的位移,这种设计,方便了程序段在内存中的浮动装配
CALL和RET指令:都是转移指令,他们都修改IP,或同时修改CS和IP。
他们经常被共同用来实现子程序的设计
CPU执行ret指令时,进行下面两步操作
·(IP)=((ss)* 16 +(SP))
·(SP)=(SP)+ 2
CPU执行retf指令时,执行下面4步操作
·(IP)=((ss)* 16 +(SP))
·(SP)=(SP)+ 2
·(CS)=((ss)* 16 +(SP))
·(SP)=(SP)+ 2
先进CS,再进IP,先弹IP,再弹CS
CPU执行CALL指令时,进行两步操作
·将当前的IP或CS和IP压入栈中
·转移
call 标号(将当前的IP压入栈中,转移到标号处执行指令)
call far ptr 标号:实现的是段间转移
(1)·(sp)=(sp)-2
·((ss)* 16 +(sp))=(cs)
·(sp)=(sp)- 2
·((ss)* 16 +(sp))=(ip)
(2)·(cs)= 标号所在段的段地址
·(ip)= 标号在段中的偏移地址
call 16位 reg:转移地址在寄存器中的call指令
call word ptr 内存单元地址:转移地址在内存中,近转移
call dword ptr 内存单元地址:远转移 相当于
·push CS
·pish IP
·jmp dword ptr 内存单元地址
内存单元地址可用寻址方式的任何一种格式给出
call、ret的组合使用:
可以写一个具有一定功能的程序段,称之为子程序,在需要的时候用户call转去
执行,执行完之后用ret返回call的下一条语句处继续执行
·就好像有一个类,类中有一个main的主方法,主方法中调用了本类的其他方法
mul乘法指令:
·两个相乘的数:要么都是8位,要么都是16位
·如果是8位,一个默认放在AL中,另一个放在8位reg中或内存字节单元中
·如果是16位,一个默认在AX中,另一个放在16位reg或内存字单元中
·结果:如果是8位乘法,结果默认放在AX中,
如果是16位乘法,结果高位默认在DX中,低位在AX中
mul reg
mul 内存单元:内存单元可以用不同的寻址方式给出
·mul byte ptr ds:[0]
7 6 5 4 3 2 1 0
含义 BL R G B I R G B
闪烁 ( 背景 )高亮( 前景 )
R:红色
G:绿色
B:蓝色
模块化程序设计
·在子程序开始的时候将子程序中所有要用到的寄存器内容保存到栈中,在子程序返回
之前恢复。不管这个寄存器中的数据是否有用,都要保存起来
功能:进行不会产生溢出的除法运算,被除数为dword型,除数为word型,结果是dword型
参数:(ax)= dword型数据的低16位
(dx)= dword型数据的高16位
(cx)= 除数
返回:(dx)= 结果高16位
(ax)= 结果低16位
(cx)= 余数
计算:1000000/10(f4240h/0ah)
divdw:
mov ax,4240h
mov dx,000fh
mov cx,0ah
call divdw
X:被除数,范围:[0,FFFFFFFF]
N:除数,范围:[0,FFFF]
H:X高16位,范围:[0,FFFF]
L:X低16位,范围:[0,FFFF]
int():描述性运算符,取商,比如,int(38/10)=3
rem():描述性运算符,取余数,比如,rem(38/10)=8
公式:X/N=int(H/N)*65535+[rem(H/N)*65535+L]/N
这个公式将可能产出溢出的除法运算转变为多个不会溢出的除法运算
公式中,等号右边的所有除法运算都可以用div指令来做,肯定不会溢出
第十一章 标志寄存器
CPU内部有一种特殊的寄存器(对于不同的处理机,个数和结构都可能不同)
作用:
·用来存储相关指令的某些执行结果
·用来为CPU执行相关指令提供行为依据
·用来控制CPU相关工作方式
这些寄存器被称为:标志寄存器(flag)
在8086CPU的指令集中,有的指令的执行是影响标志寄存器的,比如
·add 加法
·sub 减法
·mul 乘法
·div 除法
·inc 自加
·or 按位或
·and 按位与
这些都是运算指令(逻辑运算或算数运算)
mov push pop对标志寄存器没有影响,属于传送指令
flag:和其他寄存器不一样,其他都是用来存放数据的,都是整个寄存器具有一个含义
而flag寄存器是按位起作用的,也就是说,他的每一位都有专门的含义,记录特定的信息
(一整个flag是一个16位的寄存器,其中有些位是没有用的)
(1,3,5,12,13,14,15)没用
(0,2,4,6,7,8,9,10,11)有特殊意义
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
[] [] [] [] [Of] [DF] [IF] [TF] [SF] [ZF] [] [AF] [] [PF] [] [CF]
一共9个
ZF标志:处于第六位,0标志位。它记录相关指令执行后,其结果是否为0.
如果是0,那么ZF=1,
如果不为0,则ZF=0
比如指令:mov ax,1
sub ax,1
执行后,结果为0,则zf=1
PF标志:处于第二位,奇偶标志位。它记录相关指令执行后,其结果的所有bit中1的个数是否为偶数
如果是偶数,pf=1
如果是奇数,pf=0
如:mov al,1
add al,10
执行后1的个数是3,pf=0
SF标志:处于第七位,符号标志位,它记录相关指令执行后,其结果是否为负
如果是负数,sf=1
如果非负,sf=0
对于一个二进制数据,计算机可以将它当做无符号数据来运算,也可以当做有符号数来运算
比如:mov al,10000001B
add al,1
执行后:(al)= 10000010B (无符号运算,130)
(al)= 10000010B (有符号运算,-126)
结果都是相同的,关键在于我们的程序需要用哪一种结果
SF就是用来对有符号运算结果的一种记录,它记录数据的正负
CPU在执行add等指令时,必然影响到SF标志位的值。
CF标志:处于第0位,进位标志位,一般情况下在进行无符号数运算的时候,它记录了运算结果的
最高有效位向更高位的进位值,或从更高位的借位值。
比如指令:mov al,98h
add al,al
执行后,(al)= 30h,cf=1,cf记录了从最高有效位向更高位的进位值
OF标志:处于第11位,溢出标志位。一般情况下,of记录了有符号数运算的结果是否发生了溢出
如果发生溢出,OF=1
如果没有,OF=0
要注意CF和OF的区别:CF是对无符号数运算有意义的标志位,而OF是对有符号数运算有意义的标志位
比如:mov al,98
add al,99
执行后,CF=0,OF=1
DF标志和串传送指令
DF标志:处于第10位,方向标志位。在串处理指令中,控制每次操作后si,di的增减。
如果 df=1,每次操作后si,di递减
如果 df=0,每次操作后si,di递增
串传送指令:
格式:movsb (mov s byte)
功能:执行movsb相当于进行下面几步操作
·((es)* 16 +(di))=((ds)* 16 +(si))
·如果df=0 则 (si)=(si)+ 1
(di)=(di)+ 1
·如果df=1 则 (si)=(si)- 1
(di)=(di)- 1
·是将ds:si指向的内存单元中的字节送入es:di中,然后根据标志寄存器df的值
将si和di递增或递减
也可以传送一个字
指令:movsw (mov s word)
功能:是将ds:si指向的内存单元中的字送入es:di中,然后根据标志寄存器df的值
将si和di递增2或递减2
一般来说movsb和movsw都和rep配合使用
格式:rep movsb
用汇编语言描述就是:s:movsb
loop s
rep 根据cx的值循环执行串传送指令
adc指令:
格式:adc 操作对象1,操作对象2
功能:操作对象1 = 操作对象1 + 操作对象2 + CF
CF的值的含义。在执行adc指令的时候加上的CF的值的含义,是由adc指令前面的指令决定的,
CPU提供adc指令的目的就是来进行加法的第二步运算的,add和adc指令配合可以对更大的数据
进行加法运算
add ax,bx
等同于
add al,bl
adc ah,bh
比如指令:adc ax,bx
执行后:(ax)=(ax)+(bx)+ CF
inc和loop指令不影响CF位,所以在进行[si]之类的操作的时候要避免add si,2以免产生进位
sbb指令:
格式:sbb 操作对象1,操作对象2
功能:操作对象1 = 操作对象1 - 操作对象2 - CF
cmp指令:执行后将对标志寄存器产生影响。其他相关指令通过识别这些被影响的标志寄存器来
得知比较结果
格式:cmp 操作对象1,操作对象2
功能:计算操作对象1-操作对象2 但并不保存结果,仅仅根据计算结果对标志寄存器进行设置
比如:cmp ax,ax 做减法运算结果为0,但并不在ax中保存,仅影响flag相关各位。指令执行后
zf=1,pf=1,sf=0,cf=0,of=0
通过做减法运算,影响标志寄存器,标志寄存器的相关位记录了比较的结果。
和add,sub一样,CPU在执行cmp运算的时候,也包含两种含义:无符号和有符号。
检测比较结果的条件转移指令
所有条件转移指令的转移位移是[-128,127]
大部分条件转移指令都检测标志寄存器的相关标志位,根据检测的结果来决定是否修改IP。
检测的就是被cmp指令影响的那些,表示比较结果的标志位。
NV UP EI PL NZ NA PO NC
↑ ↑ ↑ ↑ ↑ ↑
OF DF SF ZF PF CF
标志 值为1的标记 值为0的标记
of OV NV
sf NG PL
zf ZR NZ
pf PE PO
cf CY NC
df DN UP
第十二章 内中断
CPU内部有下面的情况发生的时候,将产生相应的中断信息:
·除法错误,比如,执行div指令的产生的除法溢出 0
·单步执行 1
·执行into指令 4
·执行int指令 格式:int n(n为字节型立即数)
中断类型码:标识中断信息的来源,为一个字节型数据
中断源:产生中断信息的事件
中断向量表:中断向量的列表(中断处理程序的入口地址的列表)
中断向量:中断处理程序的入口地址
中断向量表指定放在内存地址0处。
从内存0000:0000到0000:03FF的1024个单元中存放着中断向量表。不能放在别处,这是规定
因为8086CPU就从这个地方读取中断向量表。
256个类型码需要1024个存储单元,一个类型码占4个单元,两个高的字节为CS,两个低的为IP
8086收到中断信息后,所引发的中断过程:
·(从中断信息中)取得中断类型码
·标志寄存器的值入栈(因为在中断过程中要改变标志寄存器的值,所以先将其保存在栈中)
·设置标志寄存器的第8位TF和第9位IF值为0(后面介绍)
·CS入栈
·IP入栈
·从内存地址为中断类型码*4和中断类型码*4+2的两个字单元中读取中断处理程序的入口地址
设置IP和CS
中断处理程序的编写方法:
·保存用到的寄存器
·处理中断
·恢复用到的寄存器
·用iret指令返回
iret指令的功能用汇编描述为
pop ip
pop cs
popf
寄存器入栈的顺序是标志寄存器,cs,ip,而出栈顺序是ip,cs,标志寄存器
第十三章 int中断
int n:n为中断类型码,它的功能是引发中断过程
中断例程:中断处理程序
BIOS和DOS所提供的中断例程
BIOS包含:
硬件系统的检测和初始化程序
外部中断和内部中断的中断例程
用于对硬件设备进行I/O操作的中断例程
其他和硬件系统相关的中断例程
从操作系统的角度看,DOS的中断例程就是操作系统向程序员提供的编程资源。
和硬件设备相关的DOS中断例程中,一般都调用了BIOS的中断例程
开机:CPU加电,初始化(cs)=0FFFFH,IP=0,自动从此处执行程序,
FFFF:0处有一条跳转指令,CPU执行该指令后,转去执行BIOS中的硬件系统
检测和初始化程序
初始化程序建立BIOS所支持的中断向量,即将BIOS提供的中断例程的入口地址登记
在中断向量表。对于BIOS所提供的中断例程,只需要登记入口地址,因为它们是
固化到ROM中的程序,一直在内存中存在
硬件系统检测和初始化完成后,调用int 19h进行操作系统的引导。从此将计算机交给
操作系统控制
DOS启动后,除完成其他工作外,还将它所提供的中断例程装入内存,并建立相应表
一般来说,一个供程序员调用的中断例程中往往包括多个子程序,中断例程内部用传递进来的
参数来决定执行哪一个子程序。BIOS和DOS提供的中断例程,都用ah来传递内部子程序的编号。
第十四章 端口
在in和out指令中,只能使用ax或al来存放从端口中读入的数据或要发送到端口中的数据。访问
8位端口时用al,访问16位端口时用ax
对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端口写入一个字节
CMOS RAM芯片:
特征:
·包含一个实时钟和一个有128个存储单元的RAM存储器(早期的计算机为64个字节)
·芯片靠电池供电。所以,关机后其内部的实时钟仍可正常工作,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号单元:
·将2送入端口70h
·从端口71h读出2号单元的内容
shl和shr:
逻辑位移指令
shl:将一个寄存器或内存单元的数据向左移位
将最后移出的一位写入cf(进位标志位)中
最低位用0补充
指令:mov al,01001000b
shl al,1 ;将al中的数据左移一位
执行后:(al)=10010000b,cf=0
如果移动位数大于1时,必须将移动位数放在cl中
比如指令:mov al,01001000b
mov cl,3
shl al,cl
cf记录最后移出的一位
左移一位相当于x=x*2
shr刚好相反
CMOS RAM中存储的时间信息
在CMOS RAM中,存放着当前的时间:年、月、日、时、分、秒。
这六个信息的长度都为一个字节,存放单元为:
秒:0 分:2 时:4 日:7 月:8 年:9
这些数据以BCD码的方式存放
BCD码是以4位2进制数表示十进制数的编码方法:
十进制数:0 1 2 3 4 5 6 7 8 9
BCD: 0000 0001 0010 0011 0100 0101 0110 0111 1000 1001
一个字节可表示两个BCD码。
第十五章 外中断
接口芯片和端口
外设接口芯片的内部有若干寄存器,CPU将这些寄存器当做端口来访问。
外设的输入不直接送入内存和CPU,而是送入相关的接口芯片的端口中;CPU向外设的输出也
不是直接送入外设,而是先送入端口中,再由相关的芯片送到外设。CPU还可以向外设输出
控制命令,而这些控制命令也是先送到芯片的端口中,然后再由相关的芯片根据命令对外设
实施控制。
可见,CPU通过端口和外部设备进行联系。
在PC系统中,外中断源一共有以下两类
1、可屏蔽中断
可屏蔽中断是CPU可以不响应的外中断。CPU是否响应可屏蔽中断,要看标志寄存器的IF
的设置。当CPU检测到可屏蔽中断的信息时,如果IF=1,则CPU在执行完当前指令后响应
中断,引发中断过程,如果IF=0,则不响应可屏蔽中断
2、不可屏蔽中断
不可屏蔽中断是CPU必须响应的外中断。当CPU检测到不可屏蔽中断信息时,则在执行完当前
指令后,立即响应,引发中断过程。
对于8086CPU,不可屏蔽中断的中断类型码固定为2,所以中断过程中,不需要取中断类型码。
几乎所有由外设引发的外中断,都是可屏蔽中断。当外设有需要处理的事件(比如说键盘输入)
发生时,相关芯片向CPU发出可屏蔽中断信息。不可屏蔽中断是在系统中有必须处理的紧急情况
发生时用来通知CPU的中断信息。在我们的课程中,主要讨论可屏蔽中断。
PC机键盘的处理过程
1、键盘输入
键盘上的每一个键相当于一个开关,键盘中有一个芯片对键盘上的每一个键的开关状态进行扫描
按下一个键时,开关接通,该芯片就产生一个扫描码,扫描码说明了按下的键在键盘上的位置。
扫描码被送入主板上的相关接口芯片的寄存器中,该寄存器的端口地址为60h
松开按下的键时,也产生一个扫描码,扫描码说明了松开的键在键盘上的位置。松开按键时产生
的扫描码也被送入60h端口中
一般将按下一个键时产生的扫描码称为通码,松开一个键产生的扫描码称为断码。扫描码长度为
一个字节,通码的第七位为0,断码的第七位为1,即:
断码=通码+80h
2、引发9号中断
键盘的输入到达60h端口时,相关的芯片就会向CPU发出中断类型码为9的可屏蔽中断信息。CPU
检测到该中断信息后,如果IF=1,则响应中断,引发中断过程,转去执行int9中断例程。
3、执行int9中断例程,用来进行基本的键盘输入处理,主要的工作如下:
·读出60h端口中的扫描码
·如果是字符键的扫描码,将该扫描码和它所对应的字符码送入内存中BIOS键盘缓冲区;如果是
控制键(比如ctrl)和切换键(比如CapsLock)的扫描码,则将其转变为状态字节(用二进制位
记录控制键和切换键状态的字节)写入内存中存储状态字节的单元
·对键盘系统进行相关的控制,比如说,向相关芯片发出应答信息
第十六章 直接定址表
通过给出的数据进行计算或比较而得到结果的问题,转化为用给出的数据作为查表的依据,通过查表
得到结果的问题。具体的查表方法,是用查表的依据数据,直接计算出索要查找的元素在表中的位置。
像这种可以通过依据数据,直接计算出所要找的元素的位置的表,我们称其为直接定址表。
程序入口地址的直接定址表
在直接定址表中存储子程序的地址,从而方便不同子程序的调用。
d:查看内存中的内容
e:改写内存中的内容
u:将机器码转为汇编语言
t:执行一条语句
a:以汇编指令的格式写入机器指令
g:将使debug从当前cs:ip处开始执行
p:自动执行循环
Debug的T命令在执行修改寄存器ss的指令时,下一条指令也跟着被执行
assume:假设某一段寄存器和程序中的某一个用segment...ends定义的段相关联
可能会出现子程序,可以将子程序和主程序链接成一个程序,
ax,bx,cx,dx;
si,di,sp,bp,ip;
cs,ss,ds,es,psw
指令:
mov 转移指令
jmp 跳转指令
add 加法指令
sub 减法指令
push 入栈
pop 出栈
inc 自增1
and 逻辑与指令,按位进行与运算,通过该操作可以将操作对象的相应位设为0,其他位不变
小写变大写,用and指令将第五位置0,其余都是1
or 逻辑或指令,按位进行或运算,通过该操作可以将操作对象的相应位设为1,其他位不变
大写变小写,用or指令将第五位置1,其余都是0
div 除法指令
jmp 跳转指令 (无条件转移指令) 只修改IP时,称为段内转移,比如:jmp ax
同时修改CS和IP时,称为段间转移,比如:jmp 1000:0(源程序中不可这么写)
由于转移指令对IP的修改范围不同,段内转移又分为:短转移和近转移
·短转移IP的修改范围为-128—127
·近转移IP的修改范围为-32768—32767
jmp 寄存器:只修改IP
jmp 段地址:偏移地址
nop 空指令,什么也不做
jcxz 有条件转移指令
loop 循环指令:所有循环指令都是短转移
dec 自减指令 和inc相反
ret和retf
·ret指令用栈中的数据,修改IP的内容,从而实现近转移
·retf指令用栈中的数据,修改CS和IP的内容,从而实现远转移
call 转移指令,不能实现短转移。实现转移的方法和jmp指令的原理相同
mul 乘法指令
adc 带进位加法指令,利用了CF位上记录的进位值
abb 带借位减法指令,利用了CF位上记录的进位值
cmp 比较指令(compare),相当于减法指令,只是不保存结果
有关cmp的信息
指令 含义 检测的相关标志位
je e:equal 等于则转移 zf=1
jne ne:not equal 不等于则转移 zf=0
jb b:below 低于则转移 cf=1
jnb nb:not blow 不低于则转移 cf=0
ja a:above 高于则转移 cf=0且zf=0
jna na:not above 不高于则转移 cf=1或zf=1
rep 根据cx的值,重复执行后面的串传送指令。由于每执行一次movsb指令si和di都会
递增或者递减指向后一个或前一个单元,则rep movsb就可以循环实现(cx)个字符的传送
rep movsw同理
cld、std 只对df位进行设定的指令(单独使用)
cld 将标志寄存器df位置0,递增
std 将标志寄存器df位置1,递减
pushf和popf:为直接访问标志寄存器提供了一种方法
pushf 将标志寄存器的值压栈
popf 将数据从栈中弹出送入标志寄存器中
iret 返回中断程序
int 引发中断过程
in/out 端口读/写指令,只有这两条
shl和shr 逻辑位移指令
shl 逻辑左移
shr 逻辑右移
sti 设置IF=1
cli 设置IF=0
ax,bx,cx,dx:通用寄存器
可分为高8位和低8位
cs,ds,ss,es:段寄存器
cs和ip:
cs:代码段寄存器
ip:指令指针寄存器
任意时刻,将cs:ip指向的内容当做指令执行
ds和[]:
ds:数据段寄存器
[]:表示一个内存单元。表示一个偏移地址
ss和sp:
ss:存放栈顶的段地址(栈顶寄存器)
sp:存放栈顶偏移地址
任意时刻,ss:sp指向栈顶元素
[bx]和loop:
[bx]和[0]有些类似,表示一个内存单元,它的偏移地址在bx中
约定符号idata表示常量
段前缀:用于显式地指明内存单元的短地址
一段安全的空间:0:200 - 0:2ff这段空间是安全的
dw:define word,定义一个字型数据
db:define byte 定义一个字节型数据
dd:(dword) double word 定义一个双字型数据
dup:和dw、db、dd等数据定义的伪指令配合使用,用来进行数据的重复
比如:db 3 dup (0) 定义了3个字节,它们的值都是0,相当于db 0,0,0
用法:数据定义 重复的次数 dup (重复的数据定义类型数据)
si、di和bx功能差不多,但是不能分割成两个8位的
将计数的内容暂时放到内存中,开辟一段内存空间
reg:表示一个寄存器
sreg:表示一个段寄存器
reg:ax,bx,cx,dx,ah,al,bh,bl,ch,cl,dh,dl,sp,bp,si,di
sreg:ds,ss,cs,es
只要在[]中使用寄存器bp,而没有显性地给出段地址,段地址默认在ss中
bp、bx不能同时出现,si、di也是
SA:段地址
EA:偏移地址
寻址方式:当数据放在内存中的时候,我们可以用多种方式来给定这个内存单元的偏移地址
这种定位内存单元的方法一般称为寻址方式
(汇编语言 表8.2)
直接寻址:[idata],用立即数进行寻址
寄存器间接寻址:[bx]、[bp]、[si]、[di],使用寄存器进行寻址
寄存器相对寻址:[bx+idata]、[bp+idata]、[si+idata]、[di+idata],相对某个值
基址变址寻址:[bx+si]、[bp+si]、[bx+di]、[bx+di],在原有基址的基础上都可以改变,都是变量
相对基址变址寻址:[bx+si+idata]、[bp+si+idata]、[bx+di+idata]、[bx+di+idata],加上相对值
通过寄存器名指明要处理的数据的尺寸
在没有寄存器名存在的情况下,用操作符X ptr指明内存单元的长度,X在汇编指令中可以位word或byte
做除法时应注意下列问题
1、除数:有8位和16位两种,在一个reg或内存单元中
2、被除数:默认放在AX或DX和AX中,如果除数为8位,被除数为16位,
默认放在AX中;如果除数为16位,被除数则为32位,在DX和AX中存放,DX存高16位
AX存低16位
3、结果:如果除数为8位,则AL存商,AH存余数
如果除数为16位,则AX存商,DX存余数
转移指令:可以修改IP,或同时修改CS和IP的指令。
可以控制CPU执行内存中某处代码的指令
转移指令可分为:
·无条件转移指令:jmp
·条件转移指令
·循环指令:loop
·过程
·中断
操作符:offset
·由编译器处理的符号,功能是取得标号的偏移地址
seg
·取得某一标号的段地址
jmp指令要给出两种信息
·转移的目的地址
·转移的距离(段间转移、段内短转移,段内近转移)
段内短转移:jmp short 标号 (转到标号处执行指令)对IP的修改范围为-128-127
CUP在执行jmp指令的时候并不需要转移的目的地址,相对当前IP的转移位移
段内近转移:jmp near ptr (IP)=(IP)+16位位移
段间转移:jmp far ptr 远转移
jmp word ptr 内存单元地址:(段内转移)
·从内存单元地址处开始存放着一个字,是转移的目的偏移地址
jmp dword ptr 内存单元地址:(段间转移)
·从内存单元地址处开始存放着两个字,低地址是转移的目的偏移地址,高地址是段地址
jmp的转移地址可以放在3个地方:
·地址在伪指令中--就是标号(s、s0)
·地址在寄存器中(ax、bx)
·地址在内存中(如上)
内存单元地址可用寻址方式的任何一种格式给出
jcxz指令格式:jcxz 标号(如果cx=0,转移到标号处执行)
如果(cx)不等于0,什么也不做(程序向下执行)
loop指令格式:loop 标号
转移包含的信息是目的地址的位移,这种设计,方便了程序段在内存中的浮动装配
CALL和RET指令:都是转移指令,他们都修改IP,或同时修改CS和IP。
他们经常被共同用来实现子程序的设计
CPU执行ret指令时,进行下面两步操作
·(IP)=((ss)* 16 +(SP))
·(SP)=(SP)+ 2
CPU执行retf指令时,执行下面4步操作
·(IP)=((ss)* 16 +(SP))
·(SP)=(SP)+ 2
·(CS)=((ss)* 16 +(SP))
·(SP)=(SP)+ 2
先进CS,再进IP,先弹IP,再弹CS
CPU执行CALL指令时,进行两步操作
·将当前的IP或CS和IP压入栈中
·转移
call 标号(将当前的IP压入栈中,转移到标号处执行指令)
call far ptr 标号:实现的是段间转移
(1)·(sp)=(sp)-2
·((ss)* 16 +(sp))=(cs)
·(sp)=(sp)- 2
·((ss)* 16 +(sp))=(ip)
(2)·(cs)= 标号所在段的段地址
·(ip)= 标号在段中的偏移地址
call 16位 reg:转移地址在寄存器中的call指令
call word ptr 内存单元地址:转移地址在内存中,近转移
call dword ptr 内存单元地址:远转移 相当于
·push CS
·pish IP
·jmp dword ptr 内存单元地址
内存单元地址可用寻址方式的任何一种格式给出
call、ret的组合使用:
可以写一个具有一定功能的程序段,称之为子程序,在需要的时候用户call转去
执行,执行完之后用ret返回call的下一条语句处继续执行
·就好像有一个类,类中有一个main的主方法,主方法中调用了本类的其他方法
mul乘法指令:
·两个相乘的数:要么都是8位,要么都是16位
·如果是8位,一个默认放在AL中,另一个放在8位reg中或内存字节单元中
·如果是16位,一个默认在AX中,另一个放在16位reg或内存字单元中
·结果:如果是8位乘法,结果默认放在AX中,
如果是16位乘法,结果高位默认在DX中,低位在AX中
mul reg
mul 内存单元:内存单元可以用不同的寻址方式给出
·mul byte ptr ds:[0]
7 6 5 4 3 2 1 0
含义 BL R G B I R G B
闪烁 ( 背景 )高亮( 前景 )
R:红色
G:绿色
B:蓝色
模块化程序设计
·在子程序开始的时候将子程序中所有要用到的寄存器内容保存到栈中,在子程序返回
之前恢复。不管这个寄存器中的数据是否有用,都要保存起来
功能:进行不会产生溢出的除法运算,被除数为dword型,除数为word型,结果是dword型
参数:(ax)= dword型数据的低16位
(dx)= dword型数据的高16位
(cx)= 除数
返回:(dx)= 结果高16位
(ax)= 结果低16位
(cx)= 余数
计算:1000000/10(f4240h/0ah)
divdw:
mov ax,4240h
mov dx,000fh
mov cx,0ah
call divdw
X:被除数,范围:[0,FFFFFFFF]
N:除数,范围:[0,FFFF]
H:X高16位,范围:[0,FFFF]
L:X低16位,范围:[0,FFFF]
int():描述性运算符,取商,比如,int(38/10)=3
rem():描述性运算符,取余数,比如,rem(38/10)=8
公式:X/N=int(H/N)*65535+[rem(H/N)*65535+L]/N
这个公式将可能产出溢出的除法运算转变为多个不会溢出的除法运算
公式中,等号右边的所有除法运算都可以用div指令来做,肯定不会溢出
第十一章 标志寄存器
CPU内部有一种特殊的寄存器(对于不同的处理机,个数和结构都可能不同)
作用:
·用来存储相关指令的某些执行结果
·用来为CPU执行相关指令提供行为依据
·用来控制CPU相关工作方式
这些寄存器被称为:标志寄存器(flag)
在8086CPU的指令集中,有的指令的执行是影响标志寄存器的,比如
·add 加法
·sub 减法
·mul 乘法
·div 除法
·inc 自加
·or 按位或
·and 按位与
这些都是运算指令(逻辑运算或算数运算)
mov push pop对标志寄存器没有影响,属于传送指令
flag:和其他寄存器不一样,其他都是用来存放数据的,都是整个寄存器具有一个含义
而flag寄存器是按位起作用的,也就是说,他的每一位都有专门的含义,记录特定的信息
(一整个flag是一个16位的寄存器,其中有些位是没有用的)
(1,3,5,12,13,14,15)没用
(0,2,4,6,7,8,9,10,11)有特殊意义
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
[] [] [] [] [Of] [DF] [IF] [TF] [SF] [ZF] [] [AF] [] [PF] [] [CF]
一共9个
ZF标志:处于第六位,0标志位。它记录相关指令执行后,其结果是否为0.
如果是0,那么ZF=1,
如果不为0,则ZF=0
比如指令:mov ax,1
sub ax,1
执行后,结果为0,则zf=1
PF标志:处于第二位,奇偶标志位。它记录相关指令执行后,其结果的所有bit中1的个数是否为偶数
如果是偶数,pf=1
如果是奇数,pf=0
如:mov al,1
add al,10
执行后1的个数是3,pf=0
SF标志:处于第七位,符号标志位,它记录相关指令执行后,其结果是否为负
如果是负数,sf=1
如果非负,sf=0
对于一个二进制数据,计算机可以将它当做无符号数据来运算,也可以当做有符号数来运算
比如:mov al,10000001B
add al,1
执行后:(al)= 10000010B (无符号运算,130)
(al)= 10000010B (有符号运算,-126)
结果都是相同的,关键在于我们的程序需要用哪一种结果
SF就是用来对有符号运算结果的一种记录,它记录数据的正负
CPU在执行add等指令时,必然影响到SF标志位的值。
CF标志:处于第0位,进位标志位,一般情况下在进行无符号数运算的时候,它记录了运算结果的
最高有效位向更高位的进位值,或从更高位的借位值。
比如指令:mov al,98h
add al,al
执行后,(al)= 30h,cf=1,cf记录了从最高有效位向更高位的进位值
OF标志:处于第11位,溢出标志位。一般情况下,of记录了有符号数运算的结果是否发生了溢出
如果发生溢出,OF=1
如果没有,OF=0
要注意CF和OF的区别:CF是对无符号数运算有意义的标志位,而OF是对有符号数运算有意义的标志位
比如:mov al,98
add al,99
执行后,CF=0,OF=1
DF标志和串传送指令
DF标志:处于第10位,方向标志位。在串处理指令中,控制每次操作后si,di的增减。
如果 df=1,每次操作后si,di递减
如果 df=0,每次操作后si,di递增
串传送指令:
格式:movsb (mov s byte)
功能:执行movsb相当于进行下面几步操作
·((es)* 16 +(di))=((ds)* 16 +(si))
·如果df=0 则 (si)=(si)+ 1
(di)=(di)+ 1
·如果df=1 则 (si)=(si)- 1
(di)=(di)- 1
·是将ds:si指向的内存单元中的字节送入es:di中,然后根据标志寄存器df的值
将si和di递增或递减
也可以传送一个字
指令:movsw (mov s word)
功能:是将ds:si指向的内存单元中的字送入es:di中,然后根据标志寄存器df的值
将si和di递增2或递减2
一般来说movsb和movsw都和rep配合使用
格式:rep movsb
用汇编语言描述就是:s:movsb
loop s
rep 根据cx的值循环执行串传送指令
adc指令:
格式:adc 操作对象1,操作对象2
功能:操作对象1 = 操作对象1 + 操作对象2 + CF
CF的值的含义。在执行adc指令的时候加上的CF的值的含义,是由adc指令前面的指令决定的,
CPU提供adc指令的目的就是来进行加法的第二步运算的,add和adc指令配合可以对更大的数据
进行加法运算
add ax,bx
等同于
add al,bl
adc ah,bh
比如指令:adc ax,bx
执行后:(ax)=(ax)+(bx)+ CF
inc和loop指令不影响CF位,所以在进行[si]之类的操作的时候要避免add si,2以免产生进位
sbb指令:
格式:sbb 操作对象1,操作对象2
功能:操作对象1 = 操作对象1 - 操作对象2 - CF
cmp指令:执行后将对标志寄存器产生影响。其他相关指令通过识别这些被影响的标志寄存器来
得知比较结果
格式:cmp 操作对象1,操作对象2
功能:计算操作对象1-操作对象2 但并不保存结果,仅仅根据计算结果对标志寄存器进行设置
比如:cmp ax,ax 做减法运算结果为0,但并不在ax中保存,仅影响flag相关各位。指令执行后
zf=1,pf=1,sf=0,cf=0,of=0
通过做减法运算,影响标志寄存器,标志寄存器的相关位记录了比较的结果。
和add,sub一样,CPU在执行cmp运算的时候,也包含两种含义:无符号和有符号。
检测比较结果的条件转移指令
所有条件转移指令的转移位移是[-128,127]
大部分条件转移指令都检测标志寄存器的相关标志位,根据检测的结果来决定是否修改IP。
检测的就是被cmp指令影响的那些,表示比较结果的标志位。
NV UP EI PL NZ NA PO NC
↑ ↑ ↑ ↑ ↑ ↑
OF DF SF ZF PF CF
标志 值为1的标记 值为0的标记
of OV NV
sf NG PL
zf ZR NZ
pf PE PO
cf CY NC
df DN UP
第十二章 内中断
CPU内部有下面的情况发生的时候,将产生相应的中断信息:
·除法错误,比如,执行div指令的产生的除法溢出 0
·单步执行 1
·执行into指令 4
·执行int指令 格式:int n(n为字节型立即数)
中断类型码:标识中断信息的来源,为一个字节型数据
中断源:产生中断信息的事件
中断向量表:中断向量的列表(中断处理程序的入口地址的列表)
中断向量:中断处理程序的入口地址
中断向量表指定放在内存地址0处。
从内存0000:0000到0000:03FF的1024个单元中存放着中断向量表。不能放在别处,这是规定
因为8086CPU就从这个地方读取中断向量表。
256个类型码需要1024个存储单元,一个类型码占4个单元,两个高的字节为CS,两个低的为IP
8086收到中断信息后,所引发的中断过程:
·(从中断信息中)取得中断类型码
·标志寄存器的值入栈(因为在中断过程中要改变标志寄存器的值,所以先将其保存在栈中)
·设置标志寄存器的第8位TF和第9位IF值为0(后面介绍)
·CS入栈
·IP入栈
·从内存地址为中断类型码*4和中断类型码*4+2的两个字单元中读取中断处理程序的入口地址
设置IP和CS
中断处理程序的编写方法:
·保存用到的寄存器
·处理中断
·恢复用到的寄存器
·用iret指令返回
iret指令的功能用汇编描述为
pop ip
pop cs
popf
寄存器入栈的顺序是标志寄存器,cs,ip,而出栈顺序是ip,cs,标志寄存器
第十三章 int中断
int n:n为中断类型码,它的功能是引发中断过程
中断例程:中断处理程序
BIOS和DOS所提供的中断例程
BIOS包含:
硬件系统的检测和初始化程序
外部中断和内部中断的中断例程
用于对硬件设备进行I/O操作的中断例程
其他和硬件系统相关的中断例程
从操作系统的角度看,DOS的中断例程就是操作系统向程序员提供的编程资源。
和硬件设备相关的DOS中断例程中,一般都调用了BIOS的中断例程
开机:CPU加电,初始化(cs)=0FFFFH,IP=0,自动从此处执行程序,
FFFF:0处有一条跳转指令,CPU执行该指令后,转去执行BIOS中的硬件系统
检测和初始化程序
初始化程序建立BIOS所支持的中断向量,即将BIOS提供的中断例程的入口地址登记
在中断向量表。对于BIOS所提供的中断例程,只需要登记入口地址,因为它们是
固化到ROM中的程序,一直在内存中存在
硬件系统检测和初始化完成后,调用int 19h进行操作系统的引导。从此将计算机交给
操作系统控制
DOS启动后,除完成其他工作外,还将它所提供的中断例程装入内存,并建立相应表
一般来说,一个供程序员调用的中断例程中往往包括多个子程序,中断例程内部用传递进来的
参数来决定执行哪一个子程序。BIOS和DOS提供的中断例程,都用ah来传递内部子程序的编号。
第十四章 端口
在in和out指令中,只能使用ax或al来存放从端口中读入的数据或要发送到端口中的数据。访问
8位端口时用al,访问16位端口时用ax
对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端口写入一个字节
CMOS RAM芯片:
特征:
·包含一个实时钟和一个有128个存储单元的RAM存储器(早期的计算机为64个字节)
·芯片靠电池供电。所以,关机后其内部的实时钟仍可正常工作,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号单元:
·将2送入端口70h
·从端口71h读出2号单元的内容
shl和shr:
逻辑位移指令
shl:将一个寄存器或内存单元的数据向左移位
将最后移出的一位写入cf(进位标志位)中
最低位用0补充
指令:mov al,01001000b
shl al,1 ;将al中的数据左移一位
执行后:(al)=10010000b,cf=0
如果移动位数大于1时,必须将移动位数放在cl中
比如指令:mov al,01001000b
mov cl,3
shl al,cl
cf记录最后移出的一位
左移一位相当于x=x*2
shr刚好相反
CMOS RAM中存储的时间信息
在CMOS RAM中,存放着当前的时间:年、月、日、时、分、秒。
这六个信息的长度都为一个字节,存放单元为:
秒:0 分:2 时:4 日:7 月:8 年:9
这些数据以BCD码的方式存放
BCD码是以4位2进制数表示十进制数的编码方法:
十进制数:0 1 2 3 4 5 6 7 8 9
BCD: 0000 0001 0010 0011 0100 0101 0110 0111 1000 1001
一个字节可表示两个BCD码。
第十五章 外中断
接口芯片和端口
外设接口芯片的内部有若干寄存器,CPU将这些寄存器当做端口来访问。
外设的输入不直接送入内存和CPU,而是送入相关的接口芯片的端口中;CPU向外设的输出也
不是直接送入外设,而是先送入端口中,再由相关的芯片送到外设。CPU还可以向外设输出
控制命令,而这些控制命令也是先送到芯片的端口中,然后再由相关的芯片根据命令对外设
实施控制。
可见,CPU通过端口和外部设备进行联系。
在PC系统中,外中断源一共有以下两类
1、可屏蔽中断
可屏蔽中断是CPU可以不响应的外中断。CPU是否响应可屏蔽中断,要看标志寄存器的IF
的设置。当CPU检测到可屏蔽中断的信息时,如果IF=1,则CPU在执行完当前指令后响应
中断,引发中断过程,如果IF=0,则不响应可屏蔽中断
2、不可屏蔽中断
不可屏蔽中断是CPU必须响应的外中断。当CPU检测到不可屏蔽中断信息时,则在执行完当前
指令后,立即响应,引发中断过程。
对于8086CPU,不可屏蔽中断的中断类型码固定为2,所以中断过程中,不需要取中断类型码。
几乎所有由外设引发的外中断,都是可屏蔽中断。当外设有需要处理的事件(比如说键盘输入)
发生时,相关芯片向CPU发出可屏蔽中断信息。不可屏蔽中断是在系统中有必须处理的紧急情况
发生时用来通知CPU的中断信息。在我们的课程中,主要讨论可屏蔽中断。
PC机键盘的处理过程
1、键盘输入
键盘上的每一个键相当于一个开关,键盘中有一个芯片对键盘上的每一个键的开关状态进行扫描
按下一个键时,开关接通,该芯片就产生一个扫描码,扫描码说明了按下的键在键盘上的位置。
扫描码被送入主板上的相关接口芯片的寄存器中,该寄存器的端口地址为60h
松开按下的键时,也产生一个扫描码,扫描码说明了松开的键在键盘上的位置。松开按键时产生
的扫描码也被送入60h端口中
一般将按下一个键时产生的扫描码称为通码,松开一个键产生的扫描码称为断码。扫描码长度为
一个字节,通码的第七位为0,断码的第七位为1,即:
断码=通码+80h
2、引发9号中断
键盘的输入到达60h端口时,相关的芯片就会向CPU发出中断类型码为9的可屏蔽中断信息。CPU
检测到该中断信息后,如果IF=1,则响应中断,引发中断过程,转去执行int9中断例程。
3、执行int9中断例程,用来进行基本的键盘输入处理,主要的工作如下:
·读出60h端口中的扫描码
·如果是字符键的扫描码,将该扫描码和它所对应的字符码送入内存中BIOS键盘缓冲区;如果是
控制键(比如ctrl)和切换键(比如CapsLock)的扫描码,则将其转变为状态字节(用二进制位
记录控制键和切换键状态的字节)写入内存中存储状态字节的单元
·对键盘系统进行相关的控制,比如说,向相关芯片发出应答信息
第十六章 直接定址表
通过给出的数据进行计算或比较而得到结果的问题,转化为用给出的数据作为查表的依据,通过查表
得到结果的问题。具体的查表方法,是用查表的依据数据,直接计算出索要查找的元素在表中的位置。
像这种可以通过依据数据,直接计算出所要找的元素的位置的表,我们称其为直接定址表。
程序入口地址的直接定址表
在直接定址表中存储子程序的地址,从而方便不同子程序的调用。