该汇编课程的研究重点放在如何利用硬件系统结构和指令集有效灵活地控制系统进行工作。
第一章 基础知识
1. 机器语言是机器指令的集合。机器指令展开来讲就是一台机器可以正确执行命令。汇编指令是机器指令的助记符,同机器指令一一对应。
汇编语言的主体是汇编指令。汇编指令和机器指令的差别在于指令的表达方式上。汇编指令是机器指令便于记忆的书写格式。
2. 每一种CPU都有自己的汇编指令集。
汇编语言发展至今,由以下三类指令组成:
1汇编指令:机器码的助记符,有对应的机器码;
2伪指令: 没有对应的机器码,由编译器执行,计算机并不执行;
3其他符号:如:+,--,*,/等,由编译器识别,没有对应的机器码。
3. CPU可以直接使用的信息在存储器中存放。
4. 在存储器中指令和数据没有任何区别,都是二进制信息。
5. 存储单元从零开始顺序编号。
6. 一个存储单元可以存储8个bit(用作单位写为“b”),即8位二进制数
7. 1B=8b 1KB=1024b 1MB=1024KB 1GB=1024MB 1TB=1024GB
8. 每一个CPU芯片都有许多管脚,这些管脚和总线相连,也可以说这些管脚引出总线。一个CPU可以引出总线的宽度标志了这个CPU的不同方面的性能:
V地址总线的宽度决定了CPU的寻址能力;
Vv数据总线的宽度决定了CPU与其他器件进行数据传送时的
一次数据传送量;
Vvv控制总线的宽度决定了CPU对系统中其他器件的控制能力;
9. 在每一台PC机中,都有一个主板,主板上有核心器件和一些主要器件,这些器件通过总线相连。这些器件有:CPU,存储器,外围芯片组,扩展插槽等。扩展插槽上一般插有RAM内存条和各类接口卡。
10. CPU对外部设备都不能直接控制,直接控制这些设备进行工作的是插在扩展插槽上的接口卡。扩展插槽通过总线和CPU相连,所以接口卡液通过总线同CPU相连。即CPU通过总线向接口卡发送命令,接口卡根据CPU的命令控制外设进行工作。
11. 随机存储器RAM,可读可写,但是必须带电存储,关机后存储的内容丢失;只读存储器ROM,只能读取不能写入,关机后其中的内容不丢失。
存储器从功能和连接上分为:
* 随机存储器:用于存放供CPU使用的绝大部分程序和数据,主随机存储器一般由装在主板上的RAM和插在扩展插槽上的RAM组成。
* 装有BIOS的ROM:BIOS是由主板和各类接口卡厂商提供的软件系统,可以通过它利用该硬件设备进行最基本的输入输出。
* 接口卡上的RAM:某些接口卡需要对大批量输入,输出数据进行暂时存储,在其上装有RAM。典型如显示卡上的RAM,一般称为显存,我们将需要显示的内容写入显存,就会出现在显示器上。
12. 对CPU 来讲,系统中的所有存储器中的存储单元都处于一个统一的逻辑存储器中,它的容量受CPU寻址能力的限制。这个逻辑存储器即是我们所说的内存地址空间。
第二章 寄存器(CPU工作原理)
1. 所有的内存单元构成的存储空间是一个一维的线性空间,每一个内存单元在这个空间中都有唯一的地址,我们将这个唯一的地址称为物理地址,CPU通过地址总线送入存储器的必须是一个内存单元的物理地址
2. 8086CPU有20位地址总线,可以传送20位地址,达到1MB的寻址能力。
3. 8086CPU在内部用两个16位地址合成的方法形成一个20位的物理地址,地址加法器采用:物理地址=段地址×16+偏移地址 的方法用段地址和偏移地址合成物理地址。其本质含义为:CPU在访问内存时,用一个基础地址和一个相对于基础地址的偏移地址相加,给出内存单元的物理地址。
4. 段地址在8086CPU的段寄存器中存放,当8086CPU要访问内存时,由段寄存器提供内存单元的段地址,8086CPU有4个段寄存器,其中CS用来存放指令的段地址。
5. CS存放指令的段地址,IP存放指令的偏移地址。
8086机中,任意时刻,CPU将CS:IP指向的内容当作指令执行。
6. 8086CPU的工作过程:
(1).从CS:IP指向的内存单元读取指令,读取的指令进入指令缓冲器;
(2).IP 指向下一条指令;
(3).执行指令。(转到步骤(1),重复这个过程)
7. 8086CPU提供转移指令修改CS,IP的内容。
第三章 寄存器(内存访问)
1. 字在内存中存储时,要用两个地址连续的内存单元存放,字的低位字节存放在低地址单元中,高位字节存放在高地址单元中
2. 用mov指令要访问内存单元,可以在mov指令中只给出单元的偏移地址,此时,段地址默认在DS寄存器中。
3. 【address】表示一个偏移地址为address的内存单元。
4. 在内存和寄存器之间传送字型数据时,高地址单元和高8位寄存器,低地址单元和低8位寄存器相对应。
5. mov ,add ,sub 是具有两个操作对象的指令,jmp是具有一个操作对象的指令。
6. 8086CPU提供了栈操作机制,方案如下:
在SS,SP中存放栈顶的段地址和偏移地址;
提供出栈和入栈指令,他们根据SS:SP提示的地址,按照栈的方式访问内存单元。
7. push指令的执行步骤:1. SP=SP-2 ; 2. 向SS:SP指向的字单元中送入数据。
8. pop指令的执行步骤: 1. 从SS:SP指向的字单元读取数据;2. SP=SP+2;
9. 任意时刻,SS:SP指向栈顶元素。
10. 8086CPU只记录栈顶,栈科技的大小我们要自己管理。
11. 用栈来暂存以后需要恢复的寄存器的内容时,寄存器出栈的顺序要和入栈的顺序相反。
12. push 和pop实质上是一种内存传送指令,注意他们的灵活应用。
13. 段的综述
我们可以将一段内存定义为一个段,用一个段地址指示段,用偏移地址访问段内的单元,这完全是我们自己的安排。
我们可以用一个段存放数据,将它定义为“数据段”;
我们可以用一个段存放代码,将它定义为“代码段”;
我们可以用一个段当作栈,将它定义为“栈段”;
我们可以这样安排,但是若要让CPU按照我们的安排来访问这些段,就要:
对于数据段,将它的段地址放在DS中,用mov , add ,sub 等访问内存单元的指令时,CPU就将我们定义的数据段中的内容当作数据来访问;
对于代码段,将它的段地址放在CS中,将段中的第一条指令的偏移地址放在IP中,这样CPU就将执行我们定义的代码段中的指令;
对于栈段,将它的段地址放在SS中,将栈顶单元的偏移地址放在SP中,这样CPU在需要进行栈操作的时候,比如执行push ,pop指令等,就将我们定义的栈段当作栈空间来使用。
可见,不管我们如何安排,CPU将内存中的某段内容当作代码,是因为CS:IP指向了那里;CPU将某段内存当作栈,是因为SS:SP 指向了那里。
14. 一段内存,可以既是代码的存储空间,又是数据的存储空间,还可以是栈空间,也可以什么也不是。关键在于CPU中寄存器的设置,即:CS IP ,SS SP ,DS的指向。
第四章 第一个程序
汇编语言从写出到执行的简要过程:
第一步 编写汇编源程序
结果产生了一个存储源程序的文本文件
第二步 对源程序进行编译连接
编译生成目标文件————连接生成可执行文件
可执行文件包含两部分内容:
¥. 程序(从源程序中的汇编指令翻译过来的机器码)和数据(源程序中定义的数据)
¥. 相关的描述信息(比如,程序有多大,要占用多少内存空间等)
这一步工作的结果是产生了一个可在操作系统中运行的可执行文件
第三步 执行可执行文件中程序
操作系统依照可执行文件中的描述信息,将可执行文件中机器码和数据加载入内存,并进行相关的初始化(比如设置CS:IP指向第一条要执行的指令),然后由CPU执行程序。
程序加载后,cx中存放的是程序的长度,DS中存放着程序所在内存区的段地址,这个内存区的偏移地址为0,则程序所在的内存区的地址为 DS:0;
这个内存区的前256个字节中存放的是PSP ,DOS用来和程序进行通信。从256字节处向后的空间存放的是程序。
第五章 【BX】和loop指令
1. 完整地描述一个内存单元需要两种信息:¥.内存单元的地址 ;¥.内存单元的长度(类型)
2. loop 标号 ,CPU执行loop指令的时候,要进行两步操作:¥.(cx)=(cx)-1;¥.判断CX中的值,不为零则跳转至标号处执行程序,如果为零则向下执行。标号代表一个地址。
3. 用CX和loop指令相配合实现循环功能要点:
(1) 在CX中存放循环次数;
(2) Loop指令中的标号所标识地址要在前面;
(3) 要循环执行的程序段,要写在标号和loop指令的中间。
第六章 多个段
1. 可执行文件中的程序执行过程:
¥. 由其他的程序(debug,command或其他程序)将可执行文件中的程序加载入内存;
¥. 设置CS:IP指向程序的第一条要执行的指令(即程序的入口),从而使程序得以运行;
¥. 程序运行结束后,返回到加载者。
end start 指明的程序入口,被转化为一个入口地址,存储在可执行文件的描述信息中。
第七章 内存定位
1.¥. and 逻辑与指令,按位进行与运算
通过该指令可将操作对象的相应位设为0,其他位不变
将AL的第六位设为0:and al,10111111B
¥. Or 逻辑或指令,按位进行或运算
通过该指令可将操作对象的相应位设为1,其他位不变
将AL的第六位设为1:or al,01000000B
2. A :41H,01000001B ;a : 61H,01100001B.
就ASCII码的二进制形式来看,除第5位外,大写字母和小写字母的其他各位都一样。
大写字母的ASCII码第五位为0,小写字母的第五位为1.
4. SI和DI是8086CPU中和bx功能近似的寄存器,SI和DI不能够分成两个8位寄存器来使用。
第八章 数据处理
1. 四个寄存器:BX SI DI BP 这四个寄存器可以单个出现,或只能以四种组合出现:BX和SI ,BX和DI ,BP和SI ,BP和DI。使用寄存器BP,而指令中没有显性地给出段地址,段地址就默认在SS中。
Mov ax,[bp] : (ax)=((ss)*16+(bp))
Mov ax,[bp+si+idata] : (ax)=((ss)*16+(bp)+(si)+idata)
2. 数据处理:读取,写入,运算。
机器指令并不关心数据的值是多少,而关心指令执行前一刻,它将要处理的数据所在的位置。指令在执行前,所要处理的数据可以在三个地方:CPU内部,内存,端口
Mov bx,[0] 内存,ds:0单元
Movbx,ax CPU内部,ax寄存器
Mov bx,1 CPU内部,指令缓冲器
3. 8086CPU的指令,可以处理两种尺寸的数据,byte 和word。所以在机器指令中要指明,指令进行的是字操作还是字节操作。
¥. 通过寄存器名指明要处理的数据的尺寸;
¥. 没有寄存器名存在的情况下,用操作符byte ptr 和 word ptr指明内存单元的长度
4. DIV除法指令,使用时需知:
¥. 除数:有8位和16位两种,在一个寄存器或内存单元中
¥. 被除数:除数为8位:被除数为16位,默认在AX中存放;
除数为16位:被除数则为32位,在DX和AX中存放,DX存放高16位,AX存放低16位。
¥. 结果:如果除数为8 位,则AL存储除法操作的商,AH存储除法操作的余数;如果除数为16位,则AX存储除法操作的商,DX存储除法操作的余数。
5. dup操作符,同db,dw,dd等一样,是由编译器识别处理的符号。它是和db,dw,dd等数据定义伪指令配合使用的,用来进行数据的重复。
Db/dw/dd 重复的次数 dup (重复的字/字节/双字数据)
Db 3 dup (‘abc’, ‘ABC’)
第九章 转移指令
1. 转移指令:可以控制CPU执行内存中某处的代码的指令。
8086CPU的转移行为分为:
¥. 只修改IP时,称为段内转移,如:jmp ax。
*短转移:IP的修改范围-128——127
*近转移:IP的修改范围-32768——32767
¥.同时修改CS和IP 时,称为段间转移,如:jmp 1000:0。
8086CPU的转移指令分为:
¥. 无条件转移指令(如:jmp)
¥. 条件转移指令
¥. 循环指令(如:LOOP)
¥. 过程
¥. 中断
2. offset操作符,在汇编语言中是由编译器处理的符号,它的功能是取得标号的偏移地址。
Mov ax,offset start ;取得标号start的偏移地址,送ax
3. 依据位移进行转移的JMP指令
Jmp short 标号 (转到标号处执行指令)
实现的是段内转移,它向前转移时可以最多超过128个字节,向后转移可以最多越过127个字节。
“标号”是代码段中的标号,指明了指令要转移的目的地,转移指令结束后,CS:IP应该指向标号处的指令。
指令“jmp short 标号”的功能为:(IP)=(IP)+8位位移
(1)8位位移=“标号”处的地址-jmp指令后的第一个字节的地址;
(2)short指明此处的位移为8位位移;
(3)8位位移的范围为-128——127,用补码表示;
(4)8位位移由编译程序在编译时算出。
指令“jmp near ptr 标号”功能:(IP)=(IP)+16位位移
(1)16位位移=“标号”处的地址-jmp指令后的第一个字节的地址;
(2)near ptr指明此处的位移为16位位移,进行的是段内近转移;
(3)16位位移的范围为-32768——32767,用补码表示;
(4)16位位移由编译程序在编译时算出。
4. 转移的目的地址在指令中的JMP指令
指令“jmp far ptr 标号”实现段间转移,又称为远转移。功能:
(CS)=标号所在段的段地址;
(IP)=标号在段中的偏移地址。
5. 转移地址在寄存器中的JMP指令
指令格式:jmp 16位寄存器
功能:(IP)=( 16位寄存器)
6. 转移地址在内存中的JMP指令
(1)jmp word ptr 内存单元地址(段内转移)
功能:从内存单元地址开始存放着一个字,是转移的目的偏移地址,内存单元地址可用寻址方式的任一格式给出
如:Jmp word ptr ds:[0]
Jmp word ptr [bx] 等
(2)jmp dword ptr 内存单元地址(段间转移)
功能:从内存单元地址开始存放着两个字,高地址处的字是转移的目的段地址,低地址处是转移的目的偏移地址。
(CS)=(内存单元地址+2)
(IP)=(内存单元地址)内存单元地址可用寻址方式的任一格式给出。
如:mov ax,0123h
Mov [bx],ax
Mov word ptr [bx+2],0
Jmp dword ptr [bx]
执行后,(CS)=0,(IP)=0123H,CS:IP指向0000:0123。
6. jcxz指令 有条件转移指令。
所有的有条件转移指令都是短转移,在对应的机器码中包含转移的位移,而不是目的地址。对IP的修改范围都是:-128——127.
Jcxz 标号(如果(cx)=0,转移到标号处执行。)
操作:当(cx=0)时,(IP)=(IP)+8位位移:
8位位移=“标号”处的地址-jcxz指令后第一个字节的地址
相当于:if((cx)==0)jmpshort 标号;
7. loop指令 循环指令
所有的循环指令都是短转移,在对应的机器码中包含转移的位移,而不是目的地址。对IP的修改范围都是:-128——127.
指令格式:loop 标号((cx)=(cx)-1,如果(cx)≠0,转移到标号处执行。)
操作:1.(cx)=(cx)-1;
2. 如果(cx)≠0,(IP)=(IP)+8位位移。
如果(cx)=0,什么也不做(程序向下执行)
相当于:(cx)- -;
If((cx) ≠0)jmp short 标号;
第十章 CALL和ret指令
1. ret指令 用栈中的数据,修改IP的内容,从而实现近转移
CPU执行ret指令时,1.(IP)=((SS)*16+(SP))
2. (SP)=(SP)+2
相当于:POP IP
Retf指令 用栈中的数据,修改CS和IP 的内容,实现远转移
CPU执行retf指令时,进行下面四步操作:
1. (IP)=((SS)*16+(SP))
2. (SP)=(SP)+2
3. (CS)=((SS)*16+(SP))
4. (SP)=(SP)+2
相当于:POP IP
POP CS
2. CPU 执行CALL指令时,进行两步操作:
1.将当前的IP或CS和IP压入栈中;
2.转移
CALL 指令不能实现短转移,除此之外,和JMP指令原理相同。
$.“call 标号”(将当前IP压栈后,转到标号处执行指令)
1. (SP)=(SP)-2 ((SS)*16+(SP))=(IP)
2. (IP)=(IP)+16位位移。
相当于:PUSH IP
JMP near ptr 标号
$.“call farptr 标号”段间转移
1. (SP)=(SP)-2
((SS)*16+(SP))=(CS)
(SP)=(SP)-2
((SS)*16+(SP))=(IP)
2. (CS)=标号所在段的段地址
(IP)=标号在段中的偏移地址
相当于:push cs
Push IP
Jmp far ptr 标号
$. Call 16位寄存器,
功能:1. (SP)=(SP)-2
((SS)*16+(SP))=(IP)
(IP)=(16位寄存器)
相当于: PUSH IP
Jmp 16位寄存器
$. call wordptr 内存单元地址
相当于:push IP
Jmp word ptr 内存单元地址
$. call dwordptr 内存单元地址
相当于:push CS
push IP
Jmp dword ptr 内存单元地址
3. call 和 ret配合使用实现子程序的机制
框架如下:
Assume cs:code
Code segment
Main: :
:
Call sub1
:
Sub1: :
Call sub2
:
Ret
Sub2:
:
Ret
Code ends
End main
4. mul 乘法指令;
(1).两个相乘的数,要么都是8位,要么都是16位;如果是8位,一个默认放在AH中,另一个放在8位寄存器或内存字节单元中;如果是16位,一个默认在AX中,另一个放在16位寄存器或内存字单元中。
(2).8位乘法,结果默认放在AX中;16位乘法,结果高位默认在DX中存放,低位在AX中存放。
5. 避免寄存器冲突的:
在子程序的开始将子程序中所有用到的寄存器中的内容都保存起来,在子程序返回前再恢复。
标准框架:
子程序开始:子程序中使用的寄存器入栈
子程序内容
子程序中使用的寄存器出栈
返回(ret,retf)
第十一章 标志寄存器
1. 标志寄存器flag作用:
(1) 用来存储相关指令的某些执行结果
(2) 用来为CPU执行相关指令提供行为依据
(3) 用来控制CPU的相关工作方式
8086CPU的标志寄存器有16位,其中存储的信息通常被称为程序状态字(PSW),flag是按位起作用的,每一位都有专门的含义,记录特定的信息。
12 |
11 |
10 |
9 |
8 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
|
OF |
DF |
IF |
TF |
SF |
ZF |
|
AF |
|
PF |
|
CF |
Flag的1,3,5,12,13,14,15在8086CPU中每一使用,不具有任何含义。
2. 第6位ZF,零标志位。它记录相关指令执行后,其结果是否为0。如果结果为0,那么ZF=1,不为0,那么ZF=0.影响标志寄存器的指令,如:add,sub,div,inc,mul,or,and等,他们大都是运算指令;有的指令对标志寄存器没有影响,比如:mov,push,pop等,他们大都是传送指令。
3. 第2位PF,奇偶标志位。它记录相关指令执行后,其结果的所有二进制中1的个数是否为偶数。如果1的个数为偶数,PF=1,如果为奇数,那么PF=0.
4. 第7位SF,符号标志位。它记录相关指令执行后,其结果(实际结果(寄存器中存放的结果)并非逻辑结果)是否为负。如果结果为负,SF=1,如果非负,SF=0。CPU在执行ADD等指令的时候,包含了两种含义。将得到用同一种信息记录的两种结果,关键在于我们的程序需要哪一种结果。SF标志就是CPU对有符号数运算结果的一种记录,它记录数据的正负。在我们将数据当作有符号数来运算的时候,可以通过它来得知结果的正负。如果我们将数据当作无符号数来运算,SF的值则没有意义,虽然相关的指令影响了它的值。
5. 第0位CF,进位标志位。一般情况下,在进行无符号数运算的时候,它记录了运算结果的最高位向更高位的进位值,或从更高位的借位值。
6. 第11位OF,溢出标志位。一般情况下,OF记录了有符号数运算的结果是否发生了溢出。如果发生溢出,OF=1,如果没有,OF=0。CF 是对无符号数运算有意义的标志位,而OF是对有符号数运算有意义的标志位。
7. adc带进位加法指令,它利用了CF位上记录的进位值。
指令格式:adc 操作对象1,操作对象2
功能:操作对象1=操作对象1+操作对象2+CF
加法:1低位相加;2高位相加再加上低位相加产生的进位值
下面指令和add ax,bx具有相同的结果
Add al,al
Adc ah,ah
8. sbb 带借位减法指令,它利用了CF位上记录的借位值。
格式:sbb 操作对象1,操作对象2
功能:操作对象1=程序对象1-程序对象2-CF
Sbb ax,bx实现的功能:(ax)=(ax)-(bx)-CF
9. cmp 比较指令,cmp的功能相当于减法指令,只是不保存结果。Cmp指令执行后,将对标志寄存器产生影响。其他相关指令通过识别这些被影响的标志寄存器位来得知比较结果。
格式:cmp 操作对象1,操作对象2
功能:计算操作对象1-操作对象2 但并不保存结果,仅仅根据计算结果对标志寄存器进行设置。
cmp ax,bx ;无符号数的比较
如果(ax)=(bx)则(ax)-(bx)=0,所以:ZF=1;
如果(ax)≠(bx)则(ax)-(bx)≠0,所以:ZF=0;
如果(ax)<(bx)则(ax)-(bx)将产生借位,所以:CF=1;
如果(ax)≥(bx)则(ax)-(bx)不必借位,所以:CF=0;
如果(ax)>(bx)则(ax)-(bx)既不借位,结果又不为0,所以:CF=0并且ZF=0
如果(ax)≤(bx)则(ax)-(bx)既可能借位,结果可能为0,所以:CF=1或ZF=1。
有符号数的比较:SF只能记录实际结果的正负,发生溢出的时候,实际结果的正负不能说明逻辑上真正结果的正负。但是逻辑上的结果的正负,才是cmp指令所求的真正结果,所以我们在考察SF的同时考察OF,就可以得知逻辑上真正结果的正负,同时就知道比较的结果。
1. 如果SF=1,而OF=0
没有溢出,逻辑结果的正负=实际结果的正负
SF=1,实际结果为负,(ax)<(bx)
2. 如果SF=1, 而 OF=1
OF=1,说明有溢出,逻辑上真正结果的正负≠实际正负
SF=1,实际结果为负,如果因为溢出导致了实际结果为负,则逻辑上真正的结果必然为正。
这样SF=1, OF=1,说明了(ax)>(bx)。
3. 如果SF=0,而OF=1 说明:(ax)<(bx)
OF=1,说明有溢出,逻辑结果的正负≠实际结果的正负
SF=0,实际结果非负,有溢出结果非0,所以实际结果为正,如果因为溢出导致了实际结果为正,则逻辑上真正的结果必然为负。
4. 如果SF=0,而 OF=0
没有溢出,且结果非负,所以(ax)≥(bx)
10. 检测比较结果的条件转移指令
“转移”指的是它能够修改IP,而“条件”指的是它可以根据某种条件,决定是否修改IP。这些条件转移指令通常都和CMP相配合使用,就好像call和ret指令通常相配合使用一样。
常用的根据无符号数的比较结果进行转移的条件转移指令有:
指令 含义 检测位
Je 等于则转移 ZF=1
Jne 不等于则转移 ZF=0
Jb 低于则转移 CF=1
Jnb 不低于则转移 CF=0
Ja 高于则转移 CF=0且ZF=0
Jna 不高于则转移 CF=1或ZF=1
E :equal b: below a: above n: notj: jump
11. flag 的第10位是DF,方向标志位。在串处理指令中,控制每次操作后si,di 的增减。
DF=0 每次操作后si,di 递增
DF=1 每次操作后si,di 递减
Movsb 描述:mov es:[di],byte ptrds:[si];(8086不支持这样的格式。)
如果DF=0; inc si inc di
如果DF=1; dec si dec di
功能:将ds:si指向的内存单元的字节送入es:di中,然后根据标志寄存器DF位的值,将si和di递增或递减。
Movsw 将ds:si指向的内存单元的字送入es:di中,然后根据标志寄存器DF位的值,将si和di递增2或递减2。
一般,movsb 和movsw都和rep配合使用,
格式:rep movsb
汇编描述:s: movsb
Loop s
可见,rep的作用是根据cx的值,重复执行后面的串传送指令。
8086对DF的设置:cld置0, std置1
12. pushf 将标志寄存器的值压栈,popf从栈中弹出数据,送入标志寄存器中。
第十二章 内中断
1. 任何一个通用的CPU,都具备一种能力,可以在执行完当前正在执行的指令之后,检测到从CPU外部发送过来的或内部产生的一种特殊信息,并且可以立即对所接收到的信息进行处理。这种特殊的信息,我们称其为,中断信息。
2. 四种内中断: 除法错误
单步执行
执行int0指令
执行int指令
中断信息中包含中断类型码,中断类型码为一个字节型数据,可以表示256种中断信息的来源,即中断源。
3. 中断向量表,中断处理程序的入口地址列表。
中断向量表在内存中保存,其中存放着256个中断源所对应的中断处理程序的入口。
中断向量表指定存放在内存地址0处,从0000:0000到0000:03E8的1000个段媛中存放着中断向量表。
一个表项存放着一个中断向量,也就是一个中断处理程序的入口地址,对于8086CPU,这个入口地址包括段地址和偏移地址,所以一个表项占两个字,高地址字存放段地址,低地址字存放偏移地址。
4. 8086CPU在收到中断信息后,引发的中断过程为:
1. (从中断信息中)取得中断类型码; N
2. 标志寄存器的值入栈; pushf
3. 设置标志寄存器的第八位TF和第九位IF的值为0; TF=0,IF=0
4. CS的内容入栈 ; pushCS
5. IP的内容入栈; push IP
6. 从内存地址为:中断类型码*4和中断类型码*4+2的两个字单元中读取中断处理程序的入口地址设置IP和CS。(IP)=(N*4),(CS)=(N*4+2)
在最后一步完成后,CPU开始执行程序员编写的中断处理程序。
5. CPU随时都可能执行中断处理程序,所以中断处理程序必须一直存储在内存某段空间之中。
中断处理程序的编写步骤:
1. 保存用到的寄存器
2. 处理中断
3. 恢复用到的寄存器
4. 用iret指令返回
Iret指令的功能用汇编语法描述为:
Pop IP
Pop CS
Popf
Iret指令执行后,CPU回到执行中断处理程序前的执行点继续执行程序。
6. CPU在执行完一条指令之后,如果检测到标志寄存器的TF位为1,则产生单步中断,引发中断过程。单步中断的中断类型码为1,则它引发的中断过程为: [1]取得中断类型码1;
[2]标志寄存器入栈,TF,IF设置为0;
[3]CS,IP入栈;
[4](IP)=(1*4),(CS)=(1*4+2)。
Debug提供了单步中断的中断处理程序,功能为显示所有寄存器中的内容后等待输入命令。
7. 响应中断的特殊情况:在执行完向SS寄存器传送数据的指令后,即便是发生中断,CPU也不会响应。因为,SS:SP联合指向栈顶,而对他们的设置应该连续完成,如果在执行完设置SS的指令后,CPU响应中断,引发中断过程,要在栈中压入标志寄存器、CS和IP的值,而SS改变,SP并未改变,SS:SP指向的不是正确的栈顶,将引起错误。所以CPU在执行完设置SS的指令后,不响应中断。这给连续设置SS和SP,指向正确的栈顶提供了一个时机。
因此我们将设置SS和SP 的指令连续存放,使得设置SP的质量紧接着设置SS的指令执行,而在此之前,CPU不会引发中断过程。
第十三章 INT 指令
1. int 指令格式:int n n为中断类型码,它的功能是引发中断过程
CPU执行INT N指令,相当于引发一个N号中断的中断过程:
[1]取中断类型码n
[2]标志寄存器入栈,IF=0,TF=0
[3]CS、IP入栈
[4](IP)=(N*4),(CS)=(N*4+2)
从此处转去执行N号中断的中断处理程序。
2. 在系统的ROM中存放着一套程序,称为BIOS(基本输入输出系统),BIOS中主要包括:
[1]硬件系统的检测和初始化程序;
[2]外部中断和内部中断的中断例程;
[3]用于对硬件设备进行I/O操作的中断例程;
[4]其他和硬件系统相关的中断例程。
操作系统DOS也提供了中断例程,从操作系统的角度来看,DOS的中断例程就是操作系统向程序员提供的编程资源。
程序员在编程的时候,可以用INT 指令直接调用BIOS和DOS提供的中断例程,来完成某些工作。
3. BIOS和DOS中断例程的安装:
[1] 开机后,CPU一加电,初始化(CS)=0FFFFH,(IP)=0,自动从FFFF:0单元开始执行程序,FFFF:0处有一条跳转指令,CPU执行该指令后,转去执行BIOS中的硬件系统检测和初始化程序。
[2]初始化程序将建立BIOS所支持的中断向量,即将BIOS提供的中断例程的入口地址登记在中断向量表中。注意,对于BIOS所提供的中断例程,只需将入口地址登记在中断向量表中即可,因为他们是固化到ROM中的程序,一直在内存中存在。
[3]硬件系统检测和初始化完成后,调用INT 19H进行操作系统的引导,从此将计算机交由操作系统控制。
[4]DOS启动后,除完成其他工作外,还将它所提供的中断例程装入内存,并建立相应的中断向量。
第十四章 端口
1. 在PC机系统中,和CPU通过总线相连的芯片除各种存储器外,还有:
[1]各种接口卡(如:网卡、显卡)上的接口芯片,他们控制接口卡进行工作
[2]主板上的借口芯片,CPU通过他们对部分外设进行访问
[3]其他芯片,用来存储相关的系统信息,或进行相关的输入输出处理
这些芯片中,都有一组可以由CPU读写的寄存器,他们在物理上可能处于不同的芯片中,但是他们在以下两点上相同:
[1]都和CPU的总线相连,当然是通过他们所在的芯片进行的
[2]CPU对他们进行读写的时候,都通过控制线向他们所在的芯片发出端口读写命令。
可见,从CPU的角度,将这些寄存器都当作端口,对他们进行统一的编址,从而建立了一个统一的端口地址空间。每一个端口在地址空间中都有一个地址。
2. 端口地址和内存地址一样,通过地址总线来传送,在PC系统中,CPU最多可以定位64K个不同的端口。端口地址的范围:0~65535.
端口的读写::in和out指令
In al ,60h 从60H号端口读入一个字节
在in和out指令中,只能使用ax和al来存放从端口中读入的数据或要发送到端口中的数据。访问8位端口用ax,访问16位端口用ax。
对0~255以内的端口进行读写时:
In al , 20h
Out 20h , a
对256~65535的端口读写时,端口号放在dx中
Mov dx , 3f8h
In al ,dx 从端口3F8读入一个字节
Out dx, al 向端口3F8写入一个字节
3. CMOS RAM 芯片简称CMOS 芯片特征:
[1]包含一个时钟和一个有128个存储单元的RAM存储器
[2]靠电池供电,关机后内部时钟正常工作,RAM中信息不丢失
[3]128个字节的RAM中,内部时钟占用0—0dh单元来保存时间信息,其余大部分单元用于保存系统配置信息,供系统启动时BIOS程序读取。BIOS也提供了相关的程序,使我们可以在开机的时候配置CMOS RAM中的系统信息。
[4]该芯片内部有两个端口,端口地址为70H和71H。CPU通过这两个端口来读写CMOS RAM
[5]70H为地址端口,存放要访问的CMOS RAM单元的地址;71H为数据端口,存放从选定的CMOS RAM单元中读取的数据,或要写入到其中的数据。可见,CPU对CMOS RAM的读写分两步进行,比如:读CMOS RAM的2号单元:
①将2送入端口70H
②从71H读出2号单元的内容
4. CMOS RAM中存放的时间信息
存放时间:年、月、日、时、分、秒。这6个信息的长度都是1个字节。
11 |
10 |
9 |
8 |
7 |
6 |
5 |
4 |
3 |
2 |
1 |
0 |
|
|
年 |
月 |
日 |
|
|
时 |
|
分 |
|
秒 |
这些数据以BCD码的方式存放
5. SHL是逻辑左移指令,它的功能为:
[1]将一个寄存器或内存单元的数据向左移位;
[2]将最后移出的一位写入CF;
[3]最低位用0补充。
SHR逻辑右移指令,它与SHL操作相反:
[1]将一个寄存器或内存单元的数据向右移位;
[2]将最后移出的一位写入CF;
[3]最高位用0补充。
第十五章 外中断
1. 外设的输入不直接送入内存和CPU,而是送入相关的借口芯片的端口中;CPU向外设的输出也不是直接送入外设,而是先送入端口中,再由相应的芯片送到外设。可见,CPU通过端口和外部设备进行联系。
2. 可屏蔽中断:可由标志寄存器IF位设置,如果IF=1,CPU在执行完当前指令后响应中断,引发中断过程;如果IF=0,则不响应中断。
Sti ,用于设置IF=1;
Cli 用于设置IF=0.
中断过程:1. 取中断类型码n
2. 标志寄存器入栈,IF=0,TF=0.
3. CS、IP入栈
4. (IP)=(N*4),(CS)=(N*4+2).
中断类型码是通过数据总线送入CPU 的。
3. 键盘输入的处理:键盘中有一个芯片对键盘上的每一个键的开关状态进行扫描,按下一个键时,该芯片就产生一个扫描码,称为通码。扫描码被送入主板上的相关借口芯片的寄存器中,该寄存器的端口地址为60H。松开按下的键时,也产生一个扫描码,称为断码,也被送入60H。
断码=通码+80H
扫描码长度为一个字节,通码的第7位为0,断码的第7位为1.
4. 键盘的输入到达60H端口时,相关的芯片就会向CPU发出中断类型码为9的可屏蔽中断信息。CPU检测到该中断信息后,如果IF=1,则响应中断,引发中断过程,转去执行int9中断例程。
5. BIOS提供了int9中断例程,用来进行基本的键盘输入处理,主要工作:
[1]读出60H端口中的扫描码;
[2]如果是字符键的扫描码,将该扫描码和它对应的字符码(ASCII码)送入内存中的BIOS键盘缓冲区;如果是控制键和切换键的扫描码,则将其转变成状态字节,写入内存中存储状态字的单元
[3]对键盘系统进行相关的控制,比如说,向相关芯片发出应答信息。
0040:17单元存储状态字节,该字节记录了控制键和切换键的状态。
0:右shift状态,置1表示按下
1:左shift状态,置1表示按下
2:ctrl状态,置1表示按下
3:alt状态,置1表示按下
4:scrolllock状态,置1表示scroll指示灯亮
5:Numlock状态,置1表示小键盘输入的是数字
6:capslock状态,置1表示输入大写字母
7:insert状态,置1表示出于删除态。
6. 键盘输入的处理过程:
键盘产生扫描码——扫描码送入60H端口——引发9号中断——CPU执行INT9中断例程处理键盘输入。
前三步都是由硬件系统完成的。
7. 简单延时函数
Mov dx,10h
Mov ax,0
S: subax,1
Sbb dx,0[1]
Cmp ax,0
Jne s
Cmp dx,0
Jne s
程序实现100000H次循环。
8. 指令系统总结:
[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、sar、rol、ror、rcl、rcr等,除了not指令外,其他的执行结果都影响标志寄存器的相关标志位。
[4]转移指令:可以修改IP,或同时修改CS和IP的指令:无条件转移指令——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等前缀指令配合使用。
第十六章 直接定址表
1. 描述了单元长度的标号:
a db 1,2,3,4
B dw 0
Mov al,a[si]
Mov ah,0
Add b,ax
标号a、b是同时描述内存地址和单元长度的标号。标号a,描述了地址code:0,和从这个地址开始,以后的内存单元都是字节单元;而标号b描述了地址code:4,和从这个地址开始,以后的内存单元都是字单元。
标号a,b后面没有“:”
指令:mov ax,b
相当于:mov ax,cs:[4]
指令:mov al,b
指令会引起编译错误,因为b代表的是字单元,al是8位寄存器。
2. 在其他段中使用数据标号:如果想在代码段中,直接用数据标号访问数据,则需要用伪指令assume将标号所在的段和一个段寄存器联系起来。否则编译器在编译的时候无法确定标号的段地址在哪一个寄存器中。
3. 可以将功能子程序的入口地址存储在一个表中,他们在表中的位置和功能号相对应。对应的关系为:功能号*2=对应的功能子程序在地址表中的偏移。