急需一份基于8086最小模式的8086汇编语言视频教程的数字钟,时间显示通过时间中断子程序实现,不用8086时钟频

您所在位置: &
&nbsp&&nbsp&nbsp&&nbsp
基于单片机的多功能时钟.doc 70页
本文档一共被下载:
次 ,您可全文免费在线阅读后下载本文档。
下载提示
1.本站不保证该用户上传的文档完整性,不预览、不比对内容而直接下载产生的反悔问题本站不予受理。
2.该文档所得收入(下载+内容+预览三)归上传者、原创者。
3.登录后可充值,立即自动返金币,充值渠道很便利
你可能关注的文档:
··········
··········
中文题目:基于单片机的多功能时钟设计
外文题目: THE DESIGN OF MULTIFUNCTIONAL CLOCK BASED ON SINGLE-CHIP
毕业设计(论文)共 62 页(其中:外文文献及译文20页) 图纸共0张
完成日期 2013年06月
答辩日期 2013年06月
辽宁工程技术大学
本科毕业设计(论文)学生诚信承诺保证书
本人郑重承诺:《
设计(论文)的内容真实、可靠,系本人在
指导教师的指导下,独立完成。如果存在弄虚作假、抄袭的情况,本人承担全部责任。
学生签名:
辽宁工程技术大学
本科毕业设计(论文)指导教师诚信承诺保证书
本人郑重承诺:我已按学校相关规定对
同学的毕业设计(论文)的选题与内容进行了指导和审核,确认由该生独立完成。如果存在弄虚作假、抄袭的情况,本人承担指导教师相关责任。
指导教师签名:
多功能时钟广泛应用于个人家庭,车站,码头,办公室等公共场所,成为人们日常生活中不可少的必需品。单片机模块中最常见的是数字钟,数字钟是一种用数字电路技术实现时、分、秒计时的装置。由于数字集成电路的发展和石英晶体振荡器的广泛应用,使得与机械式时钟相比具有更高的准时性和直观性,且无机械装置,具有更长的使用寿命。钟表的数字化给人们生产生活带来了极大地方便,而且大大地扩展了钟表原先的报时功能。因此,研究数字钟及扩大其应用,有着非常现实的意义。
数字钟在日常生活中最常见,应用也最广泛。本文以AT89S52芯片为核心,辅以必要的外围电路和温度传感器,设计一简易的多功能电子时钟系统。设计中以DS1302为时钟芯片,DS18B20为温度传感器,通过液晶显示器LCD1602实时显示时间及温度,通过按键设置年月日和星期以及定时闹钟,定时闹钟时间到自动发出警报。数字钟采用24小时制方式显示时间。文章的核心主要从硬件设计和软件编程两个大的方面。
关键词:时钟;单片机;LCD液晶显示
Multifunctional clock is widely used in personal family, station, wharf, office and other public places, it becomes necessary things in people daily life.Digital clock is the most common application in the module of single-chip.A digital clock is a kind of digital circuit technology implementation, minutes and seconds timing device.As the development of digital integrated circuits and quartz crystal oscillator is widely used, so compared with the mechanical clock has higher quality on time and intuitive, and without a mechanical device,and having a longer life. The digital clock brought the greatly convenient to people production the life , and greatly expanded the clocks chime of the original function.Therefore, the digital clock and expand its application, has a very realistic significance.
Digital clock in our daily lives is the most common, is the most widely applied.The main section is designed digital bell to single-chip AT89C51 core, with LCD modules, clock chips, and other functional modules. In this paper, DS1302 chip is used as the clock c
正在加载中,请稍后...8086汇编语言入门-HelloWorld - imypp - 博客园
附件下载:
   &http://pan.baidu.com/s/1i5R9qO9 & &密码:rfgk
  80x86微处理器汇编语言编程。学习任何编程语言都免不了要跨越HelloWorld这道坎,面向机器的汇编语言与面向过程/对象的高级语言不同,编码过程中对寄存器、内存的分配等细节都需要编程人员去关心;而高级语言程序如C语言、C++,即使你不知道printf具体是怎么实现的,只要掌握使用方法即可(封装成模块)。C语言的helloworld程序简单到只有一行执行语句:
     & printf("Hello,World!"); & //在屏幕缓冲区中显示"Hello,World!"一串字符
  而汇编语言的Helloworld,同样很简洁,却让很多初学者摸不到头脑;打一个简单比喻,上面的printf(.....)就好比一把手枪,字符串"Hello,World!"好比子弹,给printf装上“子弹”就能完成射击的功能。当然你也可以更换其他子弹.....汇编语言要实现往屏幕缓冲区输出字符串并显示,所需做的工作就没有这么直观容易理解了。 &汇编语言编程,面向的是“寄存器”,寄存器是计算机CPU内部的一种超高速缓存(速度胜过内存数倍,但容量极小),对数据的各种操作都由“指令”来进行,也被称作汇编指令,比如ADD &AX,BX &意思是将寄存器AX与BX的值相加,结果存放到AX;AX/BX都属于8086通用数据寄存器。更多汇编知识将在以后篇幅中讲解。
  hello.asm 源程序
1 ;<span style="color: #x86汇编语言&入门程序&
3 ;文件名Hello.asm
'Hello,World!' ,0DH,0AH,24H
SEGMENT PARA STACK
<span style="color: #
<span style="color: #6 DUP(?)
<span style="color: # SSEG
<span style="color: #
<span style="color: # CSEG
<span style="color: #
CS:CSEG,DS:DSEG
<span style="color: # BEGIN:
MOV AX,DSEG
<span style="color: #
<span style="color: #
MOV DX,OFFSET MESS
<span style="color: #
MOV AH,<span style="color: #
<span style="color: #
<span style="color: #
<span style="color: #
MOV AH,4CH
<span style="color: #
<span style="color: # CSEG
<span style="color: #
<span style="color: #
初学者首先需要知道的是,汇编语言程序由两个基本元素组成:操作码、操作数
操作码,指明要进行的操作,如加、减、乘、除....
操作数,被操作的对象,可以是数字、字符串、存储单元(变量)等
本文不对代码细节做过多的解释,因为需要很多前置知识做铺垫,才能更好的理解这段代码。
前置知识包括,二进制数制换算、CPU内存单元寻址、14个16位寄存器组、存储器分段、中断机制等等
    上面的代码编辑或复制到记事本中,另存为.asm文件,这是汇编语言的源代码文件,中间要进行汇编的操作,生成的.obj文件是目标文件,经过链接之后,才能形成最终的可执行文件.exe,整个过程与高级语言的运行过程是大致相仿的。
工具有很多,但还是推荐经典的Masm5.0,
  注:编写80x86平台的汇编语言,不要在Win-Vista\7\8.1\10的系统上操作,因为16位程序会出现兼容性问题。
& & & &   本文均在Windows XP sp3操作系统上编辑、汇编、链接、运行.
Masm5.0下载:http://pan.baidu.com/s/1hsjCcRi &密码:syqo
masm无需安装,解压到某磁盘根目录下,进入DOS操作
&Win+R输入CMD进入DOS,先用DOS命令进入MASM5.0文件目录下,同时hello.asm源文件也要复制到同一路径下。
汇编命令格式&&masm &xxx.asm 回车 & 注:DOS下不区分大小写
连续回车,表示使用默认文件名,四个回车下来,会生成Hello.obj文件;如果出现错误应当更改源文件后重新汇编,
0 Warning Errors.....表示没有错误。
没有错误后,下一步进行“Link”链接,命令格式&link xxx
注:链接时要指定文件名,就是刚刚生成的Hello.obj &可以省略后缀,名字不要省略!不然会报错
link hello 回车 三次回车后,正常情况下会生成Hello.exe &那也就是程序的最终形态,直接输入hello就运行了这个程序(不要双击运行,不然DOS窗口一闪而过看不到执行结果)
HelloWorld字符串被成功输出出来,这个程序也就完成了
源文件Hello.asm——&目标文件Hello.obj——&可执行文件Hello.exe
这就是整个过程。
另外补充一点,由asm到obj在汇编语言中,这个过程叫做“汇编Assembly”;在高级语言中叫做“编译Compile”
有的教程中会缺少堆栈段SSEG,没有堆栈段 在masm中也会报错,会提示no stack segment要注意。
&==========================================================
扫一扫关注微信公众号[Cracker之家],及时获取更多编程、逆向/破解等技术类软文资讯
        
阅读(...) 评论()总有一天,走过的路上定是百花齐放,因为汗水是不会骗人的!
汇编语言8086笔记
学到的知识,很大的一部分会被忘却,而被忘记的知识的影子却保护你避免陷入很多的错觉。——伊顿公学校长威廉·考利
为什么要学习汇编语言?
  汇编语言是很多相关课程的重要基础,比如:操作系统、接口技术等。它是底层编程语言,是计算机系统提供给用户最快最有效的语言,也是能对硬件直接编程的语言。因此,对空间和时间要求很高的程序,或需要直接控制硬件的程序,必须使用汇编语言进行程序设计。
汇编语言的特点
面向机器的低级语言,与处理器密切相关。通常是为特定的计算机或计算机系列专门设计的。
保持了机器语言的优点,具有直接和简捷的特点。
可有效地访问、控制计算机的各种硬件设备,
如磁盘、存储器、CPU、I/O端口等。
目标代码简短,占用内存少,执行速度快,是高效的程序设计语言。
经常与高级语言配合使用,应用十分广泛。
汇编语言的主要应用场合
要求执行效率高、反应快的领域,如:操作系统内核,实时系统等;
与硬件资源密切相关的软件开发,如:设备驱动程序等;
大型系统性能的瓶颈,或频繁被使用的子程序或程序段;高级绘图程序、视频游戏程序一般是用汇编语言编写的。
受存储容量限制的应用领域,如:家用电器的计算机控制功能等。
  BCD码(Binary Coded Decimal)是一种二-十进制的编码,它使用4位二进制数表示一位十进制数。最常用的BCD码是8421码,又叫NBCD码(Natural Binary Coded Decimal Code),由于4位二进制数可表示16种状态,只取前10种状态来表示十进制数码0-9,从左到右每位二进制数的权分别是8、4、2、1,因此又叫8421码。
  例如:十进制数1258对应的BCD码是1000;
反之,BCD码11 0010对应的十进制数是9872。
  压缩BCD码:用一个字节表达两位BCD码,比如 表示49。
  非压缩BCD码:将8位二进制的高4位设置为0,仅用低4位表达一位BCD码。比如01001表示49。
80x86微处理器
  80X86是美国Intel公司生产的微处理器系列。
  微处理器:把运算器和控制器集成在一个芯片上,构成的中央处理器(CPU)。
  微机:即微计算机系统,由微处理器配上存储器、输入输出设备和系统软件等构成。各硬件用系统总线连接在一起。
  系统总线包括数据总线(DB)、地址总线(AB)和控制总线(CB)三组。
基于微处理器的计算机系统构成
数据总线宽度
  数据总线宽度16位:决定了数据的传输速率。
机器字长16位
  机器字长为16位:可表示数的范围为0000~FFFFH(2^16 = 64K)
地址总线宽度
  地址总线宽度为20位:寻址空间为2^20 = 1024KB = 1MB。
8086总线的工作周期
  计算机是在时钟控制下进行工作的,若干个时钟完成一个基本操作,一个基本操作就是一个总线周期,CPU有若干种典型操作,构成相应的总线周期。如存储器的读写总线周期,I/O读写总线周期等。
  执行一条指令的时间称为指令周期,指令周期是由若干总线周期构成。
  的基本总线周期是由4个时钟周期组成,在执行WAIT指令或READY引脚输入的状态为低电平时,都需要在T3和T4之间插入1个或若干个等待时钟周期Tw。
  CPU向多路复用总线上发送地址信息,指出要寻址的内存单元地址或I/O端口地址。这期间CPU还要ALE(正向脉冲),在ALE下降沿将内存单元地址或I/O端口地址打入地址锁存器。
  CPU从总线上撤销有效地址,使地址总线低16位呈高阻状态,为数据传输做准备。总线的高4位(A19~A16)输出总线周期的状态信息,用于表示中断允许状态及正在使用的段寄存器名。
  A19~A16上的状态信息不变,地址总线低16位上出现CPU要写出的或准备读入的数据。若外设与内存来不及与总线交换数据,则应通过CPU的READY信号,在T3前沿(下降沿)之前向CPU申请插入等待状态TW,在T3及TW前沿查询READY信号,查到高电平则结束等待状态,进入下一状态。否则继续插入等待。
T4状态之总线周期结束
  在一个总线周期之后,若不立即进入下一个总线周期,即CPU不与内存或外设交换数据或者指令队列已满,系统总线处于空闲状态,CPU执行总线空闲周期,总线空闲周期一般由一个或多个时钟周期组成。
中央处理器
  CPU包含了三个部分:算术逻辑、控制逻辑、寄存器组。
总线接口部件BIU (Bus Interface Unit)
  内部设有四个段地址寄存器,一个指令指针寄存器IP,一个6字节指令队列缓冲器,20位地址加法器和总线控制电路。
  主要功能:根据执行部件EU的请求,负责从内存单元中预取指令,并将它们送到指令队列缓冲器暂存。即负责完成CPU与存储器或I/O设备之间的数据传送。
执行部件EU(Execution Unit)
  执行部件中包含算术逻辑单元(ALU)、通用寄存器、状态标志寄存器、数据暂存寄存器和执行部件的控制电路。
  主要功能:从BIU的指令队列中取出指令代码,经指令译码器译码后执行指令所规定的全部功能。执行指令所得结果或执行指令所需的数据,都由EU向BIU发出命令,对存储器或I/O接口进行读/写操作。
数据寄存器
寄存器英文名
寄存器说明
Accumulator
累加寄存器,常用于运算;在乘除等指令中指定用来存放操作数,另外,所有的I/O指令都使用这一寄存器与外界设备传送数据。
基址寄存器,常用于存放存储单元地址。计算地址的时候用作基地址寄存器,用于扩展寻址,起变址的作用。
计数寄存器,一般作为循环或串操作等指令中的隐含计数器;常用于保存计算值,如在移位指令,循环(loop)和串处理指令中用作隐含的计数器。
数据寄存器,常用来存放双字数据的高16位,或存放外设端口地址,比如双字的乘除法。存放操作数和列表数据,在某些I/O操作期间,用来,在乘除运算中有专用。
共同特点:
  这四个十六位的寄存器可以分为:
高8位:AH,BH, CH,DH;
低8位:AL,BL,CL,DL。
这两组八位寄存器可以分别寻址,并单独使用。
指针寄存器
寄存器名称
寄存器英文名
寄存器说明
Stack Pointer
堆栈指针寄存器。与SS(堆栈段寄存器)配合使用来确定堆栈段栈顶的位置,也就是说SP用于存放栈顶的偏移地址。
Base Pointer
基址指针寄存器,可用作SS的一个相对基址位置(用于存放堆栈段中某一存储单元的偏移地址。)
  说明:指针寄存器和变址寄存器只能按16位进行存取操作,主要用来形成操作数的地址,用于堆栈操作和变址运算中计算操作数的有效地址。
变址寄存器
寄存器名称
寄存器英文名
寄存器说明
Source Index
源变址寄存器可用来存放相对于DS段之源变址指针,也就是说,源操作数偏址存放在SI中。
Destination Index
目的变址寄存器,可用来存放相对于 ES段的目的变址指针,也就是说,目的操作数偏址存放在DI中。
  SI和DI一般与数据段寄存器DS联合使用,用来确定数据段中某一存储单元的地址。这两个变址寄存器有自动增量和自动减量的功能,所以用来变址是十分方便的。
  在串处理中,SI和DI作为隐含的源变址和目的变址寄存器,此时SI和DI联用,DI和附加段寄存器ES联用,分别达到了在数据段和附加段寻址的目的。
  指针寄存器和变址寄存器只能按16位进行存取操作,主要用来形成操作数的地址,用于堆栈操作和变址运算中计算操作数的有效地址。
指令指针IP(Instruction Pointer)
  指令指针IP是一个16位专用寄存器(指令指针寄存器),它指向当前需要取出的指令字节,当从内存中取出一个指令字节后,IP就自动加上指令长度的值,指向下一个指令字节。
  注意:IP指向的是指令地址的段内地址偏移量,又称偏移地址(Offset Address)或有效地址(EA,Effective Address),程序不能直接访问IP。
  任意时刻,CPU将CS:IP指向的内存单元中的内容看作指令。
标志寄存器FR(Flag Register)
  8086有一个18位的标志寄存器FR,在FR中有意义的有9位,其中6位是状态位,3位是控制位。
  标志寄存器FR:
  状态信息是由中央处理机根据计算结果自动设置的。
溢出标志位OF(overflow flag)用于反映有符号数加减运算所得结果是否溢出。如果运算结果超过当前运算位数所能表示的范围,则称为溢出。溢出时OF=1,否则OF= 0。 注意,这里所讲的溢出,只是对有符号数运算而言,对无符号数没有意义。
符号标志SF(sign flag)用来反映运算结果的符号位,它与运算结果的最高位相同。在微机系统中,有符号数采用补码表示法,所以,SF也就反映运算结果的正负号。正数SF=0,负数SF为1。注意:SF是对有符号数运算有意义的标志位。
零标志ZF(zero flag)用来反映运算结果是否为0。如果运算结果为0,则其值为1,否则其值为0。在判断运算结果是否为0时,可使用此标志位。
辅助进位标志AF(auxiliary flag)记录运算时第3位(字节运算)或第7位(字运算)产生的进位或借位值。例如,执行加法指令时第3位有进位时AF=1,否则AF=0。
奇偶标志PF(parity flag)用于反映运算结果中“1”的个数的奇偶性。当结果操作数中1的个数为偶数时PF=l,否则PF=0。
进位标志CF(carry flag)主要用来反映运算是否产生进位或借位。当最高有效位有进位或借位时CF=1,否则置CF=0。注意:CF是对无符号数运算有意义的标志位
  无符号数比较示例:
  控制标志是系统程序或用户程序根据需要用指令设置的。
方向标志DF(direction flag)位用来决定在串操作指令执行时有关指针寄存器发生调整的方向。当DF位为1时,每次操作后使变址寄存器SI和DI减量;当DF为0时,则使SI和DI增量。
中断允许标志IF(interrupt flag)位用来决定CPU是否响应CPU外部的可屏蔽中断发出的中断请求。但不管该标志为何值,CPU都必须响应CPU外部的不可屏蔽中断所发出的中断请求,以及CPU内部产生的中断请求。具体规定如下:(1)当IF=1时,CPU可以响应CPU外部的可屏蔽中断发出的中断请求; (2)当IF=0时,CPU不响应CPU外部的可屏蔽中断发出的中断请求。总的来说:IF为1时,开中断,否则关中断。
跟踪标志TF(trap flag), 也叫做陷阱标志。该标志可用于程序调试。TF标志没有专门的指令来设置或清楚。(1)如果TF=1,则CPU处于单步执行指令的工作方式,此时每执行完一条指令,就显示CPU内各个寄存器的当前值及CPU将要执行的下一条指令。(2)如果TF=0,则处于连续工作模式。总的来说:TF=1时,每条指令执行完后产生陷井,TF=0时,CPU正常工作不产生陷井。
Debug中标志位的符号表示
标志寄存器FLAGS
  这是一个存放条件码标志、控制标志和系统标志的寄存器。
段寄存器(Segment Register)
  为了运用所有的内存空间,8086设定了四个段寄存器,专门用来保存段地址:
CS(Code Segment)
代码段寄存器
代码段存放当前正在运行的程序
DS(Data Segment)
数据段寄存器
数据段存放当前正在运行程序所有的数据,如果程序使用了串处理指令,则其操作数也会存放在数据段中。处理串的时候,DS默认为源串。
SS(Stack Segment)
堆栈段寄存器
定义了堆栈所在的区域。
ES(Extra Segment)
附加段寄存器
这是一个辅助的数据区,也是串处理指令的目的操作数存放区。处理串的时候,ES默认为目的串。
  存储器是计算机的记忆部件,用来存放程序和数据。按所在的位置,存储器可以分成主存储器和辅助存储器。
  主存储器存放当前正在执行的程序和使用的数据,CPU可以直接存取,它由半导体存储器芯片构成,其成本高,容量小,但速度快。
  辅助存储器可用来长期保存大量程序和数据,CPU需要通过I/O接口访问,它由磁盘或光盘构成,其成本低,容量大,但速度较慢。
  存储器被划分为若干个存储单元,每个存储单元有一个惟一的存储器地址,从0开始顺序编号,存储单元的地址是无符号数, n位二进制数共能表示2^n个存储单元的地址。
define byte
定义字节类型变量,一个字节数据占1个字节单元,读完一个,偏移量加1
define word
定义字类型变量,一个字数据占2个字节单元,读完一个,偏移量加2
define double(word)
定义双字类型变量,一个双字数据占4个字节单元,读完一个,偏移量加4
  字地址:一个字存放到存储器要占用连续的两个字节单元。字的低字节(低8位)存放在低地址中,高字节(高8位)存放在高地址中,字单元的地址用低地址表示。
  例如:34560H的字单元的内容是1234H,而地址为78780H时字单元的内容是3332H。记作:
(34560H)=1234H
(78780H)= 3332H
  同一个地址既可以看成字节单元,也可以看作是字单元、双字单元、或者是4字单元的地址,这要根据使用情况而定。字单元地址可以是偶数,也可以是奇数。但是,在中,访问存储器(要求取数或者存数)都是以字为单元进行的,也就是说,机器是以偶地址访问存储器的。这样,对于奇地址的字单元,要取一个字需要访问二次存储器,当然,这样做需要花费较多的时间。
  存储器有这样一个特性:它的内容取之不尽的。也就是说,从某个单元取出其内容后,该单元仍然保持着原来的内容不变,可以重复取出,只有存入新的信息后,原来保存的内容就自动丢失了。
各类存储器芯片
  从读写属性上看分为两类:
随机存储器(RAM)和只读存储器(ROM)
从功能和连接上分类:
随机存储器RAM
装有BIOS的ROM
接口卡上的RAM
  所有的物理存储器被看作一个由若干存储单元组成的逻辑存储器;每个物理存储器在这个逻辑存储器中占有一个地址段,即一段地址空间;CPU在这段地址空间中读写数据,实际上就是在相对应的物理存储器中读写数据。
寄存器与存储器的比较
实模式存储器寻址
  8086CPU的地址线是20位的,这样最大可寻址空间应为220=1MB,其物理地址范围从00000H~FFFFFH。
  而8086CPU寄存器都是16位的,仅能表示地址范围
0000H ~ FFFFH(64KB) 。那么,这1MB(2^20)空间如何用16位寄存器表达呢?
  根据要求可把1M字节地址空间划成若干逻辑段。每个逻辑段必须满足两个条件:
  (1)逻辑段的起始地址(简称段首址)必须是16的倍数;
  (2)逻辑段的最大长度为64K(2^6)。
  按照这两个条件,1M字节地址空间最多可划分成64K个逻辑段,最少也要划分成16个逻辑段。逻辑段与逻辑段可以相连,也可以不连,还可以重叠。
逻辑地址(LA)和物理地址(PA)
  就是存储器的实际地址,它是指CPU和存储器进行数据交换时所使用的地址(20位)。
  是在程序中使用的地址(16位) ,它由段地址和偏移地址两部分组成。逻辑地址的表示形式为“段地址∶偏移地址”。
段地址:是指逻辑段在主存中的起始位置。
段内偏移地址:是指主存单元距离段首址的偏移量,简称偏移地址,用EA来表示,由于限定每段不超过64KB,所以偏移地址可以用16位数据表示。
物理地址形成:物理地址用PA表示, 将逻辑地址中的段地址左移4位,加上偏移地址就得到20位物理地址。
物理地址 = 段地址 x 16 + 偏移地址
错误认识:
  内存被划分成了一个一个的段,每一个段有一个段地址。
正确认识:
  内存并没有分段,段的划分来自于CPU,由于8086CPU用“(段地址×16)+偏移地址=物理地址”的方式给出内存单元的物理地址,使得我们可以用分段的方式来管理内存。
8086PC工作过程的简要描述
1)从CS:IP指向内存单元读取指令,读取的指令进入指令缓冲器;
2)IP = IP + 所读取指令的长度,从而指向下一条指令;
3)执行指令。 转到步骤 (1),重复这个过程。
在 8086CPU 加电启动或复位后( 即 CPU刚开始工作时)CS和IP被设置为CS=FFFFH,IP=0000H,即在8086PC机刚启动时,CPU从内存FFFF0H单元中读取指令执行,FFFF0H单元中的指令是8086PC机开机后执行的第一条指令。
ASMARM的专栏 -
1、双操作数指令(二地址指令)
格式:[标号:] 操作符 DST,SRC [;注释]
操作规定:
1)DST与SRC应为同种操作类型且类型明确,即同为字节类型或字类型。
2)DST不能是立即数。
3)SRC和DST不能同时为存储器操作数(mem) 。
4)操作结束后,运算结果存入DST中,SRC内容不变。
2、单操作数指令(一地址指令)
格式:[标号:] 操作符 DST [;注释]
操作规定:
1)DST类型必须明确即为字节类型或字类型,不能是模糊类型
2)操作对象为目的操作数,操作结束后结果存入DST中
3)DST不能是立即数,只能是寄存器操作数(reg) 或存储器操作数(mem)。
3、无操作数指令(零地址指令)
格式:[标号:] 操作符 [;注释]
操作规定:指令中只有操作码,不含操作数,这种指令有两种可能:
1)无需任何操作数。如停机指令(HLT)、空操作指令(NOP)等。
2)所需操作数是隐含指定的,操作时取固定操作数进行操作。如进位位置0(CLC)、方向标志置0(CLD)。
  定义:寻址方式是指寻找指令中操作数所在地址的方法。
  常用的寻址方式有:立即寻址、直接寻址、寄存器寻址、寄存器间接寻址、变址寻址、基址加变址、隐含寻址等。
  寻找指令中所需要操作数存放地址的方式或者程序转移时寻找转移地址的方式称为寻址方式,因而寻址方式有两大类:一类是数据寻址方式,另一类是转移地址寻址方式。
  由于80x86指令涉及四种操作数:立即操作数(data)、寄存器操作数(reg)、存储器操作数(mem)和隐含操作数,因此,数据寻址方式又可对应四种寻址方式,即:立即寻址、寄存器寻址、存储器寻址和固定寻址。
数据寻址方式-立即寻址
  操作数直接包含在指令中,它紧跟在指令操作码后面,它作为指令存放在存储器代码段中,这种操作数称为立即数。立即数可以是8位,也可以是16位。
AX,1234H ;(AX)=1234H
  立即寻址方式用来表示常数,它常用于给寄存器或内存单元赋初值。需要强调的是,立即寻址只能用于源操作数,不能用于目的操作数,且源操作数的长度应该与目的操作数的长度一致。
  立即数可以为8位,也可以是16位;规定立即数只能是整数,不能是小数、变量或者其他类型的数据。
数据寻址方式-寄存器寻址
  操作数直接存放在由指令指明的寄存器中。在汇编指令中直接书写寄存器名,16位寄存器操作数可以是AX、BX、CX、DX、SI、DI、BP、SP、DS、ES、SS、CS等;8位寄存器操作数只能是AH、AL、BH、BL、CH、CL、DH、DL。
  指令指针寄存器IP和标志寄存器FLAGS一般不直接出现在程序中。
  此寻址方式由于存取操作数直接从CPU内部寄存器中获得,不需访问存储器,因而指令执行的速度快。
   寄存器寻址既可用于源操作数,又可用于目的操作数,应用频率最高。
  注意:CS不能作为目的操作数,因为CS:IP控制着程序指令序列的执行顺序,不能在程序中由指令随意改变。
数据寻址方式-存储器寻址
  存储器寻址方式的操作数都是存放在除代码段以外的存储区中,一般是数据段、附加段、堆栈段中的存储单元。指令中给出的是存储单元的地址或产生存储单元地址的表达式。
  在汇编语言源程序中,存储单元地址是采用逻辑地址的形式表示的,即:段首址:段内偏移地址。段首址存放在某个段寄存器中,段内偏移地址即有效地址EA是由3个地址分量的某种组合求得,这3个地址分量是:位移量、基址(BX,BP)、变址(SI,DI) 。
  这3个地址分量的不同组合,使形成有效地址EA的方法不同,相应有以下5种不同的存储器操作数寻址方式:直接寻址、寄存器间接寻址、寄存器相对寻址、基址变址寻址、相对基址变址寻址。
直接寻址方式
  直接寻址是最简单的存储器寻址,操作数的有效地址EA由指令直接给出,只包含位移量。它主要用于存取简单变量。
  EA=2000H, 假设(DS)=3000H, 那么PA=32000H
  对使用直接寻址方式需说明以下几点:
操作数默认隐含的段为数据段 DS。
若操作数在代码段、堆栈段或附加段中,可使用段跨越前缀 。MOV
AX, ES: [2000H]
指令中操作数的EA既可以是一个数字地址,也可以是一个符号地址。当EA是一个数字时,一定要注意立即寻址方式与直接寻址方式的区别,直接寻址必须有[ ]符号。
操作数地址可由变量(符号地址)表示,
但要注意变量的属性。
VALUE DB 10
MOV AH, VALUE
MOV AX, VALUE
MOV AX, WORD PTR VALUE
  直接寻址方式适合于处理存储器的单个存储单元。例如,要处理某个存放在存储器里面的变量,可以使用直接寻址方式把变量先取到一个寄存器中,然后在进一步处理。
  80x86中,为了使指令字不要太长,规定双操作数指令的两个操作数中,只能有一个使用存储器寻址方式,这就是一个变量常常先要送到寄存器的原因了。
寄存器间接寻址
  操作数的有效地址只包含基址寄存器或者变址寄存器内容的一种成分。因此,有效地址就在某个寄存器中,而操作数则在存储器中。
  操作数的有效地址EA存放在SI、DI、BX或BP之一中,而操作数在存储器中。若用BX、SI或DI间接寻址时,则操作数默认在数据段中,用DS的内容作为段首址,操作数的物理地址为:
  若指令中使用BP间接寻址时,则用堆栈段SS的内容作为段首址,操作数的物理地址为: PA=(SS)×16 +(BP)。
AX, ES:[BX]
8086不允许使用AX、CX、DX 来存放 EA,比如:MOV AX, [CX]就是错误的。
SRC 和 DST 的字长一致,自动适应寄存器的长度。
, [ BX ] ; [BX]指示一个字节单元
, [ BX ] ; [BX]指示一个字单元
适用于数组、字符串、表格的处理(可以看成一个数组来使用),执行完一条指令后,只需修改寄存器内容就可以取出下一项处理。
寄存器相对寻址方式
  寄存器相对寻址方式也可以称为直接变址寻址方式。
  操作数的有效地址EA是指令中指定的基址寄存器或变址寄存器的内容与指令中给出的位移量之和,即
  操作数的物理地址为:
  若操作数不在默认段中,则应使用段跨越前缀明确指定。
[COUNT+SI]
适于数组、字符串、表格的处理。
基址变址寻址
  操作数的有效地址EA是指令中的基址寄存器的内容+变址寄存器的内容。
  指令格式:
MOV AX, [BX][DI]
MOV AX, [BX+DI]
MOV AX, ES:[BX][SI]
适于数组、字符串、表格的处理
必须是一个基址寄存器和一个变址寄存器的组合
相对基址变址寻址
  操作数的有效地址EA是指令中的基址寄存器的内容、变址寄存器的内容、位移量三个地址分量之和,即:
  相对基址加变址寻址方式有多种等价的书写方式,书写格式:[BX+SI+1000H]、1000H[BX+SI]、1000H[BX][SI]和1000H[SI][BX]等格式都是正确的,并且其寻址含义也是一致的,但格式:BX[1000H+SI]、SI[1000H+BX]等是错误的,即所用寄存器不能在”[“,”]”之外,该限制对寄存器相对寻址方式的书写也同样起作用。
MASK [BX] [SI]
MASK [BX+SI]
[MASK+BX+SI]
  这种寻址方式通常用于对二维数组的寻址。例如,存储器中存放着由多个记录组成的文件,则位移量可指向文件之首,基址寄存器指向某个记录,变址寄存器则指向该记录中的一个元素。这种寻址方式也为堆栈处理提供了方便,一般(BP)可指向栈顶,从栈顶到数组的首地址可以使用位移量来表示,变址寄存器可以用来访问数组中的某个元素。
  可以出现在[]中的内容是有限制的,他们必须是下列中的一个(其中idata表示一个立即数):
BX+SI+idata
BX+DI+idata
BP+SI+idata
BP+DI+idata
  其中,使用到BP的默认段寄存器为SS,其他未DS
段寄存器的使用规定
汇编语言源程序
汇编源程序:由三部分组成:汇编指令、伪指令、其他标号与符号。
指令是能被计算机识别并执行的二进制代码,它规定了计算机能完成的某一操作。
伪指令是对汇编起某种控制作用的特殊命令,其格式与通常的操作指令一样,并加在汇编程序的任何地方,但是他们并不产生机器指令。
一个汇编源程序是由多个段组成的,这些段被用来存放代码、数据或当作栈空间来使用。
注意:一个有意义的汇编程序中至少要有一个段,这个段用来存放代码。
处理器选择伪操作
选择8086指令系统
选择80286指令系统
选择保护模式下的80286指令系统
选择80386指令系统
选择保护模式下的80386指令系统
选择80486指令系统
选择保护模式下的80486指令系统
选择80586指令系统
选择保护模式下的80586指令系统
  这类伪操作一般都是放在整个程序的最前面。如果不给出,则汇编程序一般认为其默认值为.8086。
段定义伪操作
  在段定义时,如果定位类型用户未选择,就表示是隐含类型,其隐含类型是PARA。
  PARA属定位类型,是对该段起始地址定位。一般,各个逻辑段的首地址在‘节’的整数边界上(每16个存储单元叫做一节),即每个逻辑段的起始地址是16的整数倍。对于PARA—指定定位段的起始地址必须在节的整数边界。
  存储器的物理地址是由段地址和偏移地址组合而成的,汇编程序在把源程序转换为目标程序的时候,必须确定标号和变量(代码段和数据段的符号地址)的偏移地址,并且需要把有关信息通过目标模块传送给连接程序,以便连接程序把不同的段和模块连接起来,形成一个可执行的程序。
明确段与寄存器的关系:assume cs:code, ds:data, es:extra
data 定义数据段
extra 定义附加段
code 定义代码段,其中的段寄存器名必须是CS、ES、DS、SS(对于386及其后继机型还有FS和GS)中的一个。
assume cs:code, ds:data, es:extra
ds, 段地址 -& 段寄存器
1)data为段名称,也是段首地址,可自己定义
功能:定义一个段,segment说明一个段开始,ends 说明一个段结束。一个段必须有一个名称来标识,使用格式为:
段名 segment
2)明确段和段寄存器的关系。assume只是说明关联关系,并没有对段寄存器赋值,除了CS(装入程序时由CPU给出),其他段寄存器要在程序中设置。
3)mov ax,4c00h和int 21h最后两条指令所实现的功能是程序返回。
4)程序结束标志,格式:END [label],标号label 指示程序开始执行的起始地址。
伪操作(伪指令)
  伪操作是汇编程序对源程序进行汇编时处理的操作,完成处理器选择、存储模式定义、数据定义、存储器分配、指示程序开始结束等功能。
处理器选择伪操作;
功能:告诉汇编程序应该选择哪一种指令系统。
位置:一般放在整个程序的最前面,也可放在程序中所用指令的上一行。
如不给出,则默认为.8086。
段定义伪操作;
程序开始和结束伪操作;
数据定义及存储器分配伪操作;
表达式赋值伪操作;
地址计数器与对准伪操作;
基数控制伪操作。
数据定义和存储器分配伪操作
格式:[变量]
操作数 [ , 操作数 , … ]
助记符:DB DW DD DF DQ DT
例:操作数可以是常数或表达式
10,4,10H,?
100,100H,-5,?
汇编程序在汇编期间在存储器中存入数据
操作数也可以是字符串
操作数也可以是地址
ADDR_TABLE
操作数字段还可以使用复制操作符DUP来复制操作数
repeat_count DUP(operand,……,operand)
repeat_count可以是一个表达式,它的值应该是一个正整数,用来指定括号中的操作数的重复次数。
操作数?可以保留存储空间,但是不存入数据。(仅仅申请一个存储空间)
DB 100 DUP (?) ; 这里表示申请100个字单元大小的内存空间,但是不进行初始化
DB 2 DUP (0,2 DUP(1,2),3) ; 把0,1,2,1,2,3按字单元存放2次。
1234H, 5678H
AX, OPER1+1
类型不匹配
AX, WORD PTR
AL, BYTE PTR
(AX)=3402H
可以看出:同一个变量可以具有不同的类型属性。
LABEL 伪操作:
LABEL可以使同一个变量具有不同的类型属性。
  变量名
  其中变量的数据类型可以是BYTE,WORD,DWORD,标号的代码类型可以是NEAR或FAR。
  数据定义及存储器分配伪指令格式中的 “变量 “是操作数的符号地址,它是可有可无 的,它的作用与指令语句前的标号相同,区别是变量后面不加冒号。如果语句中有变量,那么汇编程序将操作数的第一个字节的偏移地址赋于这个变量。
BYTE_ARRAY
WORD_ARRAY
表达式赋值伪操作
  说明:有时程序中多次出现同一个表达式,为了方便起见,可以使用赋值伪操作给表达式赋予一个名字。、
  EQU是赋值伪指令。赋值语句仅在汇编源程序时,作为替代符号用。不产生目标代码,也不占有存储单元。
  此后,程序中凡是用到该表达式之处,都可以用表达式名来代替了。可见,EQU的引入提高了程序的可读性,也使其更加易于修改。
  格式:表达式名 EQU 表达式
  功能:给表达式赋予一个名字,在程序中用表达式名代替该表达式。
  “ = ” 伪操作 (允许重复定义)
EMP = EMP+1
  说明:EQU指令类似于C语言的#define宏,在编译前被转化。
地址计数器与ORG伪操作
地址计数器$
  地址计数器 $:保存当前正在汇编的指令的偏移地址
$+6 转向地址是 JNE 的首址 +6
$+2 转向下一条指令
$ 用在指令中时,表示本条指令的第一个字节的地址;
$ 用在伪操作的参数字段时表示地址计数器的当前值。
例如:ARRAY
1, 2 , $+4 , 3 , 4 , $+4
通过图片可以看出,地址0078保存的数据为当前地址加上4;
地址007E是当前地址加上4。
  ORG 伪操作:用来设置当前地址计数器的值。即:指定一个地址,后面的程序或数据从这个地址值开始分配。
$+8; 当前地址加8,
  EVEN伪操作使下一个变量或者指令开始于偶数字节地址。一个字的地址最好从偶地址开始,所以对于字数组为了保证其从偶地址开始,可以在其前面使用EVEN伪操作来达到这一目的。
  EVEN使下一地址从偶地址开始
‘morning’
  ALIGN伪操作为保证双字数组边界从4的倍数开始创造了条件:
4 保证下一个地址是4的倍数
2 与EVEN等价
boundary(boundary的值必须是2的幂)。
基数控制伪操作
  汇编程序默认的数是十进制数,因而除非专门指定,汇编程序把程序中出现的数均看作为十进制数。为此,当使用其他基数的时候,需要专门给以标记:
表达式 规定无标记数的基数
汇编语言程序格式
  汇编语言源程序中每个语句可以由四项组成,格式如下:
[; comment]
名字(name)项是一个符号。
操作(operation)项是一个操作码的助记符,它可以是指令、伪操作或者宏指令名。
操作数(operand)项是一个或多个表达式组成,它提供为执行所要求的操作而需要的信息。
注释(comment)项是用来说明程序或者语句的功能。;为识别注释项的开始。;也可以从一行的第一个字符开始,此时整行都是注释,常用来说明下面一段程序的功能。
  操作数项由一个或者多个表达式组成,多个操作数项之间一般用逗号分开。
  操作数项可以是常数,寄存器,标号,变量或者由表达式组成。表达式是常数,寄存器,标号,变量与一些操作符相结合的序列,可以有数字表达式和地址表达式两种。
算术操作符
  算术操作符有+,-,*,/、MOD。其中MOD是指除法运算后得到的余数。算术操作符可以用于数字或者地址表达式中,但当它用于地址表达式的时候,只有其结果有明确的物理意义的时候才是有效的结果。例如:两个地址相乘和相除是没有意义的。在地址表达式中,可以使用+或者-,但也必须注意其物理意义,例如把两个不同段的地址相加也是没有意义的。经常使用的是地址±数字量,它是有意义的,例如,SUM+1是指SUM字节单元的下一个字节单元的地址(注意:不是指SUM单元的内容加1),而SUM-1则是指SUM字节单元的前一个字节单元的地址。
逻辑与移位操作符
  逻辑操作符有AND,OR,XOR和NOT;移位操作符有SHL和SHR。他们都是按位操作的,只能用于数字表达式中。
关系操作符
Great than
Less and equal
小于或等于
Great and equal
大于或等于
关系操作符的两个操作数必须都是数字,或者同一段内的两个存储器地址。
计算结果应为逻辑值,结果为真,表示为0FFFFH;结果为假的时候,则表示为0。
数值回送操作符
  它主要有的TYPE,LENGTH,SIZE,OFFEST,SEG等等。这些操作符把一些特征或者存储器地址的一部分作为数值回送。
  格式为:TYPE expression
  如果该表达式是变量,则汇编程序将回送变量的以字节数表示的类型:DB=1,DW=2,DD=4,DF=6,DQ=8,DT=10。如果表达式是标号,则汇编程序将回送代表该标号类型的数值:NEAR=-1,FAR=-2。如果表达式是常数,则应回送0。
操作数项(表达式)
算术操作符:
+、- 、*、 /、Mod
(2) 逻辑操作符: AND、OR、XOR、NOT,移位操作符:
(3) 关系操作符: EQ、NE、LT、LE、GT、GE
(4) 数值回送操作符: TYPE、 LENGTH、 SIZE 、OFFSET、SEG、
变量 / 标号 / 常数
DB、DW、DD、DF、DQ、DT、NEAR、FAR、常数
1、2、4、6、8、10、-1、-2、0(与上面的变量对应)
属性操作符: PTR、段操作符、SHORT、THIS、HIGH、LOW、HIGHWORD、LOWWORD
格式:&类型&
功能是定义符号名为新类型。如,设内存变量D1是字节属性,把它的两个字节内容送到AX中。
功能:回送由DUP定义的变量的单元数,其它情况回送1
DUP(2)),MOV
CL,LENGTH
DR2CL的值为10H
10H,30H,MOV
BL,LENGTH
DR1BL的值为1。
变量功能:LENGTH * TYPE
OFFSET和SEG
变量 / 标号
功能:回送变量或标号的偏址 / 段址
使用DEBUG调试和运行可执行文件
在初次使用DEBUG时,可参照下列步骤进行:
1、调用DEBUG,装入用户程序
2、U命令反汇编程序,记录代码段与数据段首地址
3、R命令观察寄存器初始状态
4、以单步工作方式T开始运行程序 ,设置段寄存器的值。
5、D观察用户程序数据段初始内容
6、继续以单步工作方式运行程序
7.G连续工作方式运行程序
8.E或A修改程序和数据
9.运用断点调试程序 G
80x86指令系统
空操作指令指令格式:NOP
  说明:NOP是英语“No Operation”的缩写。NOP无操作数,所以称为“空操作”。
  执行NOP指令只使程序计数器PC加1,所以占用一个机器周期。
通用数据传送指令
  数据传送指令:MOV、XCHG、LEA、LDS、LES、PUSH、POP、PUSHF、POPF、CBW、CWD、CWDE。
栈的基本操作
  8086CPU的入栈和出栈操作都是以字为单位进行的。
push与pop指令的执行过程
  PUSH指令每次只能压入一个字(16位)。
(1)SP = SP–2;
(2)将AX中的内容送入SS:SP指向的内存单元处。
(1)将SS:SP指向的内存单元处的数据送入ax中;
(2)SP = SP+2。
每执行一次PUSH,SP指针都会减1。
  指令写法:MOV
  执行操作:(DST)&-(SRC)
  其中DST表示目的操作数,SRC表示源操作数。可以在CPU内部或者在存储器之间传送数据。
  说明:
SRC和DST的操作类型必须明确而且一致。
DST不能是立即数,而且也不能是CS。
数据传送指令是不能把数据传送给CS的,因为CS是代码段寄存器,CS如果被修改程序就无法执行。
DST、SRC也不能同时是存储器寻址。
DST、SRC也不能同时是段寄存器。
立即数不能直接送段寄存器,必须通过寄存器(比如AX)送达段寄存器。
指令的执行不影响标志位。
立即数可以直接送到存储器,但应指定存储器的类型。如:
mov byte ptr[di], 3
mov word ptr[si], 3000
mov dword ptr[bx], 0FFFFFFh
  指令格式:
OPR1, OPR2
  功能:
将操作数地址中的内容互换。
  执行操作:
  注意:
指令的执行并不影响标志位。
不允许使用段寄存器,不允许使用立即数,不支持两个存储单元之间的数据交换。
允许字或者字节操作。
累加器专用传送指令
  功能:将表格中的一个字节内容送到AL累加器中。常用于将一种代码转换为另一种代码。
  这条指令根据AL寄存器提供的位移量,将BX指使的字节表格中的代码换存在AL中。(AL)&-((DS)*16+(BX)+(AL))
  说明:本指令并不影响标志位。
TABLETABLE为表格的起始地址)
XLAT(AL)&-((BX)+(AL))
执行指令前要将TABLE先送入BX,将待查字节与在表格中距离表首地址位移量送AL。
地址传送指令
load effective address
有效地址送寄存器
load DS with pointer
指针送寄存器和DS
load ES with pointer
指针送寄存器和ES
load FS with pointer
指针送寄存器和FS
load GS with pointer
指针送寄存器和GS
load SS with pointer
指针送寄存器和SS
  功能:有效地址送寄存器。
  全称:load effective address
, [+] ------
  MOV BX, OFFSET [BX+SI] ;——× 注意:OFFSET只能与简单的符号地址相连。
  算术运算指令会根据运算结果影响状态标志,主要影响6个标志位:ZF、CF、AF、SF、OF和PF。
ADD DST,SRC
功能:加法,将SRC和DST的值相加之后存放在DST中。执行操作: (DST)
(SRC) + (DST)
ADC DST, SRC
功能:带进位的加法指令,将SRC和DST的值和进位标志位(CF)相加之后存放在DST中。执行操作:(DST)
(SRC) + (DST) + CF
功能:加一指令。执行操作:(OPR)
  说明:加法指令都会影响条件标志位,但INC指令不影响CF标志。
  INC影响的条件标志位包括:SF,ZF,OF,AF,PF。
ADC指令的作用
  在执行 adc 指令的时候加上的 CF 的值是由 adc指令前面的指令决定的,也就是说,关键在于所加上的CF值是被什么指令设置的。
  下面的指令和add ax , bx具有相同的结果:
  看来CPU提供 ADC指令的目的,就是来进行加法的第二步运算的。ADC指令和ADD指令相配合就可以对更大的数据进行加法运算。
  注意:有符号的双精度数的溢出,应根据ADC指令的OF位判断,而作低位加法用的ADD指令的溢出是无意义的。
  用16位寄存器编写程序:
AX, word ptr d1由于d1是双字类型,必须使用强制类型说明符。
DX, word ptr d1+2(DX,AX)构成一个32位数据
AX, word ptr d2低字相加,有可能会产生“进位”
DX, word ptr d2+2高字相加。
word ptr d1, AX低字送给d1的低字
word ptr d1+2, DX高字送给d1的高字
  OF位可以用来表示带符号数的溢出,CF位可以用来表示无符号数的溢出。
  条件标志(或者称呼为)位中最主要的是CF,ZF,SF,OF四位,分别表示了进位、结果为零,符号和溢出的情况。
  执行加法指令的时候,CF位是根据最高有效位是否向最高位的进位来设置的。有进位的时候CF=1,无进位的时候CF=0。
  OF位则根据操作数的符号及其变化情况来设置的:若两个操作数的符号相同,而结果的符号与之相反则OF=1,否则OF=0。
注意区分OF是根据原先的符号位来判断的。
  溢出位OF既然试试根据数的符号及其变化来设置的,当然它是用来表示带符号数的溢出的,从其设置条件来看结论也是明显的。
  CF位可以用来表示无符号数的溢出。一方面,由于无符号数的最高有效位只有数值意义而无符号意义,所以该位产生的进位应该是结果的实际的进位值,但是在有限数位的范围内就说明了结果的溢出情况;另一方面,它所保存的进位值有时候还是有用的。例如。双字长数运算的时候,可以利用进位值把低位字的进位计入高位字中。
加法的ASCII码调整指令AAA
把AL中的和调整到非压缩BCD码格式 → AL
AH + 调整产生的进位值 → AH
影响标志位:
适用于数字ASCⅡ码的调整;
也适用于一般的非压缩BCD码的十进制调整
调整原则:
①若AL的低4位是在0~9之间,且AF=0,则无需调整
②若AL的低4位是在0AH~0FH之间,或AF=1,则AL
加6调整,AH+1→ AH,且使CF=1
加法的十进制调整指令DAA
把AL中的和调整到压缩BCD码格式→ AL
影响标志位:
CF、PF、AF、ZF、SF
① DAA通常跟在ADD和ADC指令之后使用
② 只能对AL中的运算结果进行BCD码调整
SUB DST,SRC
功能:减法,将SRC和DST的值相减之后存放在DST中。执行操作: (DST)
(SRC) + (DST)
SUB DST, SRC
功能:带借位减法指令,将SRC和DST的值和进位标志位(CF)相加之后存放在DST中。执行操作:(DST)
(SRC) + (DST) - CFCF为进位位的值。
功能:加一指令。执行操作:(OPR)
功能:加一指令。执行操作:(OPR)
(OPR) + 1把操作数按位求反后末尾加1。
OPR1, OPR2
功能:加一指令。执行操作: (OPR1) - (OPR2)执行减法操作,不保存结果。往往根据比较发生转移。
  减法运算的条件码情况和加法类似。CF位说明无符号数相减的溢出,同时它又确实是被减数的最高有效位向高位的借位值。OF位则说明带符号数的溢出。
  减法的CF值反映了无符号数运算中的借位情况,因此当作为无符号运算时,若减数&被减数,此时有借位,则CF=1;否则CF=0。或者,也可以简单地用二进制减法的运算中的最高有效位向高位的进位的情况来判别:有进位的时候CF=0,没有进位的时候CF=1。
  减法的OF位的设置方法为:若两个数的符号相反,而结果的符号与减数相同则相同,则OF=1;除了上述情况外OF=0。OF=1说明带符号数的减法溢出,结果是错误的。
  NEG指令的条件码按照求补后的结果设置,只有当操作数为0的时候,求补运算的结果使得CF=0,其他情况都为CF=1。所以,只有当字运算时对-128求补的时候,以及字运算的时候对-32768求补以及双字运算的时候对-2^31求补的情况下OF=1,其他则均为OF=0。
减法的ASCII码调整指令AAS
把AL中的差调整到非压缩BCD码格式 → AL
AH - 调整产生的进位值 → AH
影响标志位:
用途:同AAA
调整原则:
①若AL的低4位是在0~9之间,且AF=0,则无需调整
②若AL的低4位是在0AH~0FH之间,或AF=1,则减6调整,AH+1→ AH,且使CF=1
减法的十进制调整指令DAS
把AL中的差调整到压缩BCD码格式→ AL
影响标志位:
CF、PF、AF、ZF、SF
DAA通常跟在SUB和SBB指令之后使用
只能对AL中的运算结果进行BCD码调整
无符号数乘法指令
带符号数乘法指令
字节操作数
(AL) * (SRC)
(DX, AX) &-
(AX) * (SRC)
AL (AX) 为隐含的乘数寄存器。
AX (DX,AX) 为隐含的乘积寄存器。 CPU会根据乘数是8位、16位,还是32位操作数,来自动选用被乘数:AL、AX或EAX。
SRC不能为立即数。
除CF和OF外,对条件标志位无定义。
当乘积的高半部分不为0时,CF=1,OF=1。
乘法的ASCII码调整指令AAM
把AL中的内容调整到非压缩BCD码格式 → AX
影响标志位:
SF,ZF,PF
调整原则:
将AL中的内容除以0AH,高八位放在AH中,低八位保存在AL中
执行AAM前必须执行MUL指令把两个非压缩的BCD码相乘(要求高4位为0),结果放在AL中
无符号数除法指令
带符号数除法指令
字节操作数
(AL) &- (AX) / (SRC) 的商(AH) &- (AX) / (SRC) 的余数
(AX) &- (DX, AX) / (SRC) 的商(DX) &- (DX, AX) / (SRC) 的余数
AX (DX,AX) 为隐含的被除数寄存器。
AL (AX) 为隐含的商寄存器。
AH (DX) 为隐含的余数寄存器。
SRC不能为立即数。
对所有条件标志位均无定义。但是可能产生溢出。
执行除法指令后,对AF,CF,OF,PF,SF,ZF标志位的影响都不确定。
除法的ASCII码调整指令AAD
把AX中的被除数调整为二进制 → AL
影响标志位:
SF,ZF,PF
调整原则:
若被除数是存放在AX中的两位非压缩BCD码,调整为二进制数
若除数是一位非压缩BCD码,调整为二进制数
指令AAD放在DIV指令前
标志寄存器传送指令
load AH with flags
将标志寄存器中的低八位送到AH中。
store AH into flags
将AH寄存器的相应位传送到标志寄存器的低8位。
PUSHF/PUSHFD
push the flags or eflags
PUPF/POPFD
pop the flags or eflags
这组指令中的LAHF和PUSHF/PUSHFD都不影响标志位。SAHF和POPF/POPFD则由装入的值来确定标志位的值,但是POPFD指令不影响VM,RF,IOPF,VIF和VIP的值。
STC----是置进位标志指令,执行的结果是将进位标志CF置1
CLC----是清进位标志指令,其执行结果是置CF标志为0
  读取标志指令LAHF:
类型转换指令
字节转换为字
AL符号扩展到AH中,形成AX中的字。即如果(AL)中的最高有效位是0,则(AH)=0;如(AL)的最高有效位为1,则(AH)=0FFH。执行操作: 若(AL)的最高有效位为0,则(AH)= 00H若(AL)的最高有效位为1,则(AH)= FFH
字转换为双字
AX符号扩展 -& (DX,AX)双字执行操作:若(AX)的最高有效位为0,则(DX)= 0000H若(AX)的最高有效位为1,则(DX)= FFFFH
双字转换为4字
EAX的内容符号扩展到EDX,形成EDX:EAX中的4字。
字节交换指令
格式:BASWAP r32。该指令只能用于486及其后继机型。r32指32位寄存器。执行的操作:使指令指定的32位寄存器的字节次序变反。具体的操作为:1、4字节互换,2
隐含对AL 或AX 进行符号扩展
本组指令都不影响条件标志位
逻辑运算指令
逻辑与格式:AND DST,SRC
逻辑或格式:OR DST,SRC
逻辑非格式:NOT DST,SRC
exclusive or
异或格式:XOR DST,SRC
作用:测试格式:TEST OPR1,OPR2执行的操作:(OPR1)∧(OPR2)说明:两个操作数相与的结果不保存,只是根据其特征置条件码。
在以上的五种指令中,NOT不允许存放立即数。
其他4条指令除非源操作数是立即数,至少有一个操作数必须存放在寄存器中,另一个操作数则可以使用任意寻址方式。
NOT不影响标志为。
其他4种指令将使CF位和OF位为0,AF位无定义,而SF位、ZF位和PF位则根据运算结果设置。
这些指令对处理操作数的某些位很有用,例如可以屏蔽某些位(将这些位置0),或者使某些位置1或者测试某些位等等。
  要求屏蔽0、1两位,可以用AND指令并设置常数0FCH。
MOV AL,0BFH
AND AL,0FCH
  这两条指令的运行结果使得(AL)=0BCH。因此,使用AND指令可以使得操作数的某些位被屏蔽。只需要把AND指令的源操作数设置成一个立即数,并把需要屏蔽的位设置为0,这样指令执行的结果就可以把操作数的相应位置0,其他位保持不变。
  要求第5位置1,可以使用OR指令。
MOV AL,43H
MOV AL,20H
  这两条指令执行了之后,(AL)=63 H。因此,用OR指令可以使得操作数的某些位置1,其他位保持不变。只需要把OR指令的源操作数设置为一个立即数,并把需要置1的位设置为1,就可以达到目的了。
  要测试操作数的某些位是否为0,可以使用TEST指令,同样把TEST指令的源操作数设置成一个立即数,其中需要测试的位应该设置为1。
MOV AL,40H
TEST AL,0AFH
  这里要求测试第0,1,2,3,5,7位是否为0,根据测试的结果设置条件码为CF=OF=0,SF=0,ZF=1,说明了所需要测试的位均为0。如果在这两条指令之后跟一条件转移指JNZ,结果如果不是0就转移,结果如果是0就顺序往下执行,这样就可以根据测试的情况产生不同的程序分支,转向不同的处理方案了。
  要测试操作数的某位是否为1,可以先把该操作数求反,然后使用TEST指令测试。如要测试AL寄存器中第2位是否为1,若为1则转移到EXIT中去执行,可以用下列指令序列:
TEST DL,0000 0100B
  如AL寄存器的内容为0FH,为了避免破坏操作数的原始内容,把它复制到了DL中去测试,执行完TEST指令之后,结果为全0而有ZF=1,说明操作数的第2位为1引起的转移到EXIT去执行。
  要是操作数的某些位变反,可以使用XOR指令,只要把源操作数的立即数字段的相应位置设置为1就可以达到目的。如果求第0,1位变反,可以使用下面的指令:
MOV AL,11H
  则指令执行后,(AL)=12H,达到了第0,1位变反而其他位不变的目的。
  XOR指令还可以用来测试某一个操作数是否与另外一个确定的操作数相等。这种操作在检查地址是否匹配的时候是经常使用的。
XOR AX,042EH
  这两条指令是用来检查AX的内容是否等于042EH,若相等则转移到MATCH去执行匹配的情况需要做的工作,否则执行JZ下面的程序。
位测试并修改指令
  386及其后继机型增加了本组指令。
位扫描指令
  386及其后继机型增加了本组指令。
移位指令-这里编辑未完成
shift logical left
shift arithmetic left
shift logical right
shift arithmetic right
rotat left
rotat right
rotate left through carry
带进位循环左移
rotate right through carry
带进位循环右移
shift left double
双精度左移
shift right double
双精度右移
OPR可用除立即数以外的任何寻址方式
移位次数CNT=1,SHL OPR, 1
CNT&1,MOV
CL, CNT,SHL OPR, CL
条件标志位:
CF = 移入的数值
CNT=1时,最高有效位的值发生变化
CNT=1时,最高有效位的值不变
循环移位指令:
不影响 SF、ZF、PF、AF
移位指令:
常用来作乘以2或除以2 的操作。
SAL:有符号数乘以2,SAR有符号数除以2;
SHL:无符号数乘以2,SHR: 无符号数除以2。
移位填充方式
右边统一添0,移出来的那一位放进CF
右边统一添0,移出来的那一位放进CF
左边统一添0,移出来的那一位放进CF
左边添加符号位上的数,移出来的那一位放进CF
  示例:,其中[]是添加的位
  逻辑左移一位:]
  算术左移一位:]
  逻辑右移一位:[0]
  算术右移一位:[1]
控制转移指令
  一般情况下指令都是顺序逐条执行的,但是实际上程序不可能全部顺序执行而经常需要改变程序的执行流程。
无条件转移指令JMP
段内直接短转移:
执行操作:(IP) ← (IP) + 8位位移量
short:表示实现的是段内直接短转移,即位移量为8位数据,它对IP的修改范围为 -128~127,也就是说,它向前转移时可以最多越过128个字节,向后转移可以最多越过127个字节。
段内直接近转移:(转向的符号地址)
执行操作:(IP) ← (IP) + 16位位移量
段内间接转移:(除立即数以外的寻址方式)
执行操作:
(IP) ← (EA)
段间直接远转移:(转向的符号地址)
执行操作:
(IP) ← OPR 的段内偏移地址
(CS) ← OPR 所在段的段地址
段间间接转移:(存储器寻址方式)
执行操作:
(IP) ← (EA)
(CS) ← (EA+2)
执行JMP指令的时候,IP改变两次。
第一次是在读取指令的时候,JMP指令被读取放到了指令缓冲期中,这个时候IP改变了一次;之后,JMP指令执行的时候进行了跳转,IP又改变了一次。所以IP总共改变了两次。
条件转移指令
  注意:只能使用段内直接寻址的8 位位移量。
   1)根据单个条件标志的设置情况转移:
JZ(JE) OPR
jump if zero,or equal
结果为0(相等)则转移
jump if not zero, or not equal
不为0(不相等)转移
jump if sign
jump if not sign
jump if overflow
jump if not overflow
不溢出转移
jump if parity, or parity even
有偶数个1则转移
jump if not parity, or parity odd
有奇数个1 则转移
jump if carry
有进位转移
jump if not cary
无进位转移
   2)比较两个无符号数,并根据比较结果转移的指令(与比较指令CMP 联用)
JB (JNAE,JC) OPR
jump if below
有借位,被减数小于减数则转移
JNB (JAE,JNC)
jump if not below
没有借位, 被减数大于或等于减数则转移
JNA (JBE) OPR
jump if not above,jump if below of equal
CF∨ZF = 1
被减数小于或等于减数则转移
JA (JNBE) OPR
jump if above,jump if not below or not equal
CF ∨ ZF = 0
被减数大于减数则转移
适用于地址或双精度数低位字的比较。
  无符号数比较示例:cmp ax,bx
  cmp指令对有符号数的比较: cmp
1、如果SF=1,而OF=0, (ah)&(bh)
OF=0,说明没有溢出,逻辑上真正结果的正负=实际结果的正负;SF=1表示实际结果为负,所以逻辑上真正的结果为负,所以(ah)&(bh)。
2、如果SF=0,而OF=1 ,(ah)&(bh)
OF=1 ,说明有溢出,逻辑上真正结果的正负≠实际结果的正负;SF=0表示由于溢出导致了实际结果非负,那么逻辑上真正的结果必然为负。这样,SF=0,OF = 1 ,说明了(ah)&(bh)。
3、如果SF=0,而OF=0, (ah)≥(bh)
OF=0,说明没有溢出,逻辑上真正结果的正负=实际结果的正负;SF=0表示实际结果非负,所以逻辑上真正的结果必然非负。所以(ah)≥(bh)。
4、如果SF=1,而OF=1, (ah)&(bh)
OF=1 ,说明有溢出,逻辑上真正结果的正负≠实际结果的正负; SF=1 表示由于溢出导致了实际结果为负,那么逻辑上真正的结果必然为正。这样,SF=1,OF = 1 ,说明了(ah)&(bh)。
  3)比较两个带符号数,并根据比较结果转移的指令
JL (JNGE) OPR
jump if less
小于,或者不大于或等于则转移。
JNL (JGE) OPR
jump if not less
不小于,或者大于或等于则转移。
JNG (JLE ) OPR
jump if not greater
(SF?OF)∨ZF = 1
不大于或者小于或等于则转移。
JG (JNLE) OPR
jump if greater
(SF?OF)∨ZF = 0
大于或者不小于或等于则转移。
适用于带符号数的比较
   4)测试 CX 的值为 0 则转移的指令
jump if CX register is zero
CX寄存器的内容为零则转移。
int sum=0;
for(int i=0;i&10;i++)
sum=sum+i;
  相当于:
// 计算0+1+2+3+4+5+6+7+8+9的值
  指令的格式是:loop 标号
  CPU 执行loop指令的时候,要进行两步操作:
  ① (cx)=(cx)-1;
  ② 判断cx中的值,不为零则转至标号处执行程序,如果为零则向下执行,退出循环。
  可见,cx中的值影响着loop指令的执行结果。用loop指令来实现循环功能时,cx 中要存放循环次数。
  一条循环指令LOOP AGAIN可以用修改循环计数和判断转移条件的两条指令替代DEC CX,JNZ AGAIN。JNZ(或JNE)结果不为零(或不相等)则转移,测试条件为ZF=0。
  我们可以总结出用cx和loop 指令相配合实现循环功能的三个要点:
1)在cx中要存放循环次数;
2)loop 指令中的标号所标识地址要在前面;
3)要循环执行的程序段,要写在标号和 loop 指令的中间。
4)loop指令的执行不影响条件码标志位。
  以上指令序列执行后ADD AX,BX指令被执行了多少次?
  答案是:65536次。
  循环 LOOP (loop)
  指令的汇编格式:LOOP label
  指令的基本功能:
  ①(CX)←(CX)-1
  ② 若(CX)≠0,则(IP)←(IP)当前+位移量,否则循环结束。
  指令的特殊要求:循环指令都是短转移格式的指令,也就是说,位移量是用8位带符号数来表示的,转向地址在相对于当前IP值的-128 ~ +127字节范围之内。
  解析:LOOP指令是先执行CX自减的功能,之后才进行循环的。只要CX不为0,循环就不会终止。因此在上面中,第一次执行的时候,CX自减为0FFFFH,这时CX就不为0的,循环不会被终止。由此,我们可以算出总共运行了65536次。
可提前结束的循环指令
当为0或相等时循环
LOOPZ / LOOPE 标号
ZF=1且(CX)≠0
不为0或不相等循环
LOOPNZ / LOOPNE 标号
ZF=0且(CX)≠ 0
执行步骤:
(CX) ← (CX) - 1;
检查是否满足测试条件,如满足则实现循环;不满足则退出循环。
CX 中存放循环次数;
与比较指令CMP联合使用可提前退出循环。
串处理指令
串处理指令
串重复前缀
设置方向标志指令
INSB / INSW
OUTSB / OUTSW
  字符串操作指令的实质是对一片连续存储单元进行处理,这片存储单元是由隐含指针DS:SI或ES:DI来指定的。
  与 REP 配合工作的MOVS / STOS / LODS / INS / OUTS。
  REP 重复串操作直到计数寄存器CX的内容为0为止。
  执行操作:
如 (CX)=0 则退出 REP,否则转(2)
(CX) &- (CX) -1
执行 MOVS / STOS / LODS / INS / OUTS
重复 (1) ~ (3)
MOVS串传送指令
  MOVS 串传送指令:
MOVSB ;(字节)
MOVSW ;(字)
MOVSD ;(双字,计数器为ECX,386及后继机型)
  例:MOVS
ES: BYTE PTR [DI],
  执行操作:
1) ((DI)) ← ((SI))
字节操作:(SI)←(SI)±1,
(DI)←(DI)±1,字操作: (SI)←(SI)±2,
(DI)←(DI)±2
(方向标志
DF=0 时用 + ,DF=1 时用 - 。)
  REP MOVS:将数据段中的整串数据传送到附加段中。源串(数据段)→ 目的串(附加段)
  执行 REP MOVS 之前,应先做好:
源串首地址(末地址)→ SI
目的串首地址(末地址)→ DI
串长度 → CX
建立方向标志CLD ( STD )
CLD 使 DF=0,从前往后处理,地址自动增量;
STD 使 DF=1 ,由后向前处理,地址自动减量)
‘personal_computer’
17 dup (?)
assume cs:code,ds:data.es:extra
  反向的指令:
si, mess1+16
di, mess2+16
  为了在同一段内处理数据,可以在DS和ES中设置同样的地址。
‘personal_computer’
17 dup (?)
STOS存入指令
  执行操作:
  字节操作:((DI))←(AL),
(DI)←(DI)±1
  字操作:((DI))←(AX),
(DI)←(DI)±2
  例:把 附加段 中mess2开始的 10 个字节缓冲区全部置为 20H
  或者:
LODS从串取指令
LODSB ;(字节)
LODSW ;(字)
执行操作:
字节操作:(AL)←((SI)),
(SI)←(SI)±1
字操作:(AX)←((SI)),
(SI)←(SI)±2
LODS 指令一般不与 REP 联用;
有时缓冲区中的一串字符需要逐次取出来测试,可使用本指令。
INS 串输入指令:
INSB (字节)
INSW(字)
执行操作:
  字节操作:((DI))←((DX)),
(DI)←(DI)±1
  字操作:((DI))←((DX)),
(DI)←(DI)±2 功能:把端口号在DX的I/O空间的字节、字或双字传送到附加段中的由DI所指向的存储单元中,并根据DF的值和数据类型修改DI的内容。
OUTS 串输出指令:
OUTSB(字节)
OUTSW(字)
执行操作:
  字节操作:((DX))←((SI)),
(SI)←(SI)±1
  字操作:((DX))←((SI)),
(SI)←(SI)±2
  功能:把由SI所指向的存储单元中的字节、字或双字传送到端口号在DX的I/O端口中去,并根据DF的值和数据类型修改SI的内容。
与 REPE / REPZ(REPNE / REPNZ)配合工作的
CMPS 和 SCAS
REPE / REPZ
当相等 /为零时重复串操作
REPNE / REPNZ
当不相等 /不为零时重复串操作
执行操作:
1) 如 (CX)=0 或 ZF=0 (ZF=1) 则退出串操作,否则转2)
2) (CX)←(CX) -1
执行 CMPS / SCAS
重复 (1) ~ (3)
CMPS 串比较指令:
CMPSB(字节)
CMPSW(字)
执行操作:
1) ((SI)) - ((DI))根据比较结果置条件标志位:相等 ZF=1,不等 ZF=0
2) 字节操作:(SI)←(SI)±1,
(DI)←(DI)±1,字操作: (SI)←(SI)±2,
(DI)←(DI)±2
  汇编语言中,CMP和CMPS都是比较指令,不同主要有:
  1、CMP比较指令是执行两个数的相减操作,包括有符号数。CMPS比较指令是执行两个字符串的相减操作,所有数据认为是无符号数。
  2、CMP比较指令必须有两个显式操作数。CMPS比较指令可以有两个显式操作数,也可以使用指令CMPSB或CMPSW分别表示字节串比较或字串比较而隐含操作数。
  3、使用CMP比较指令比较连续的数据时,必须由程序改变其中一个操作数。使用CMPS比较指令比较连续的字符时,对由SI寻址的源串中数据与由DI寻址的目的串中数据进行比较,执行完一条比较指令,SI,DI将自动调整.
  例:比较两个字符串,找出它们不相匹配的位置。
  反向比较:
si, mess1+4
di, mess2+4
SCAS 串扫描指令
SCASB (字节)
SCASW (字)
执行操作:
  字节操作:(AL) - ((DI)),
(DI)←(DI)±1
  字操作:(AX) - ((DI)),
(DI)←(DI)±2
例:从一个字符串中查找一个指定的字符
(di):相匹配字符的下一个地址
(cx):剩下还未比较的字符个数
子程序设计
int main(){
void func(){
  等价于:
ASSUME CS:CODE
CODE SEGMENT
MOV AH,4CH
  子程序:在许多应用程序中,常常需要多次使用某功能的指令序列。这时,为了减少重复编写程序,节省内存空间,把这一功能的指令序列组成一个相对独立的程序段。在程序运行时,如果需要使用这个给定的功能,就转移到这个独立的程序段,待这个独立的程序段指令序列执行完后,又返回到原来位置继续运行程序。我们把这个相对独立的程序段就叫子程序或过程。
  调用程序:编制程序时,按需要转向子程序,称为子程序调用,或称为过程调用。调用子程序的程序称为调用程序或主程序。主、子程序是相对而言的。但子程序一定是受调用程序或主程序调用的。子程序定义的位置可以放在主程序的前面或后面。
过程定义伪操作
过程名 PROC NEAR or FAR
过程名 ENDP
过程名是子程序入口的符号地址;
RET是子程序返回的命令;
NEAR属性:调用程序和子程序在同一代码段中,可省略。(段内调用)
FAR属性:调用程序和子程序不在同一代码段中。(段间调用)
同一个子程序可以被段内调用,也可以段间调用。
子程序的调用与返回指令
1)CALL 子程序调用指令:隐含使用堆栈保存返回地址
  指令格式:CAL DST其中DST为过程的目标地址(即过程名)。
  指令功能:
把CALL指令的下一条指令地址(称为返回点或断点) 推入堆栈保存,然后转到目标地址(DST)。
CALL指令可以在段内、段间调用,寻址方式分为直接和间接两种。
段内直接近调用:CALL DST
  DST给出子程序的入口地址(子程序为near属性),比如:CALL subp
  执行操作:
(SP) ← (SP) - 2
( (SP)+1,(SP) ) ← (IP)
上面两句相当于PUSH IP
(IP) ← DST
实际操作是把从指令中得到的距目标过程相对偏移量加到指令指针IP上(得到子程序的入口地址),实现过程调用。
段内间接近调用:CALL DST
  执行操作:
(IP) ← (EA)
DST给出寄存器或存储单元的内容(转向地址)
比如: CALL word ptr [bx]
段间直接远调用:CALL FAR PTR DST
  DST给出子程序的入口地址(子程序为far属性),比如:CALL far ptr subp
  执行操作:
(IP) ← DST偏移地址
(CS) ← DST段地址
段间间接远调用:CALL FAR PTR DST
  DST给出存储单元的内容(转向地址),比如: CALL dword ptr [bx]
  执行操作:
(IP) ← (EA)
(CS) ← (EA+2)
2)RET 返回主程序指令
  说明:属于无条件转移指令。可以在段内或段间返回。
段内近返回:RET
  执行操作:
段内带立即数近返回:RET EXP
  执行操作:
(SP)←(SP)+EXP
段间远返回:RET(F)
  执行操作:
现场保护和恢复
  要保护的寄存器:应该是在子程序中将被使用,返回调用程序后仍然需要使用其原有内容的那些寄存器。即保护调用程序和子程序两者在使用上发生冲突的那些寄存器。但在编程时,一时很难弄清哪些是有冲突的寄存器,一种较为简单的方法是把所有的寄存器均加以保护。
  一般在子程序中进行寄存器保护较好。即在子程序的开始部分,先进行相关寄存器(主要是在子程序中使用的各寄存器)的保护。然后再进行子程序的处理操作。在执行完子程序后,返回前,先恢复各寄存器内容后,再返回调用程序。
子程序的参数传送
  入口参数:子程序需要从主程序获取的参数。使子程序可以对不同数据进行相同功能的处理。
  出口参数:是子程序返回给主程序的参数。使子程序可以将不同的结果送至主程序
  实现的方法是把子程序所需要的入口参数,由调用程序预先放入指定的寄存器中。在进入子程序后,子程序就可直接对这些寄存器内容进行操作了。同样子程序的运行结果,也可置入寄存器中,把它们作为子程序的出口参数寄存器使用。由于寄存器数目有限,适用于参数较少的情况。
1) 通过寄存器传送参数
2) 通过存储器传送参数
3) 通过地址表传送参数地址
4) 通过堆栈传送参数或参数地址
  参数的传递方法并不是固定不变的,即它们是可以综合使用的。依实现的需要和情况的不同,可以灵活使用其中一种方式,也可以同时使用几种方式的混合。有的时候还可能并不需要参数传递。
assume cs: hexidec
cx, 10000d
mov dl, 0dh
mov dl, 0ah
  宏:源程序中一段有独立功能的程序代码。在使用之前先定义一次,以后就可以多次调用。
  宏指令:用户自定义的指令。在编程时,将多次使用的功能用一条宏指令来代替。
汇编语言源程序包含:
指令:程序运行时执行的语句
伪指令(伪操作):汇编时执行
宏指令:汇编时展开
高级语言的宏
  C语言中以#define作为标志的编译预处理命令称为宏定义命令。其不带参数的格式为:
#define 标识符 字符串
  其中的标识符叫宏名,字符串叫宏体。带参的宏一般形式为:
宏名(参数表)
area(r) (3.1415926*(r)*(r))
  系统对宏的处理是这样的:当遇到宏名时,就用宏体替换,即所谓的宏替换。这一过程是由预编译程序完成的(不必用户自己操作),而后才将宏替换后的程序交编译程序进行编译。
宏定义、宏调用和宏展开
; 宏定义:
macro_name
[哑元表] ; 形参/虚参
…… 宏定义体
  宏调用: (必须先定义后调用)macro_name
[实元表] 实参
  宏展开: 宏定义体-&复制到宏指令位置,实参代虚参。
宏和子程序的对比
模块化,省内存
参数传送简单,执行效率高
占用内存空间大
宏定义中的参数
1、宏定义可以无变元(无参数);
2、变元可以是常数、寄存器、存储单元名以及用寻址方式能找到的地址或表达式;
3、变元可以是操作码或操作码的一部分(必须用&作为分隔符);
4、变元可以是ASCII串(字符串)。
注意:宏调用时若实参个数少于形参个数会出现编译错误,若实参个数多于形参,则按形参的顺序填入实参,多余部分被忽略。
宏汇编操作符
符号1 & 符号2
宏展开时,合并前后两个符号形成一个符号。 &可以作为哑元的前缀。
宏展开的时候,;;后面的注释不予展开。
汇编程序将%后面的表达式转换为当前基数下的数字,并在展开期间用这个数取代哑元。
LOCAL伪操作
  LOCAL伪操作为每个标号建立唯一的符号(??0000~??FFFF),必须紧跟在MACRO语句之后,中间不允许有任何操作包括注释。
  说明:
  反汇编出来内容如下:
……; `absol var`的内容
1 ??0000: next的地址
……; `absol bx`的内容
1 ??0001: next的地址
  从上面可以看出使用了LOCAL伪操作之后,每次调用absol后,next的地址都是不同的。即 LOCAL伪操作为每个标号建立唯一的符号。
列表伪操作
在LST清单中列出宏展开后的全部语句(包括注释)。
在LST清单中不列出任何宏展开后的语句。
缺省的列表方式,只列出宏体中产生目标代码的语句。
宏库的建立和调用
MACRO . MAC
  &EDIT EXP.ASM
…… 删除不用的宏定义` `
输入输出程序设计
  不同外设具有的端口数各不相同,计算机中为每一个端口都赋予一个惟一编号——称为端口地址(或端口号PORT)。
8086CPU采用I/O端口独立编址的方式,采用16位地址最多能管理64K个端口,即端口占64KB地址空间,端口号为0~65535。必须使用专门的I/O指令访问端口。
  CPU与I/O接口进行通信是通过接口电路内部的一组寄存器实现的,这些寄存器称为端口,包括:数据端口、状态端口和命令端口。
累加器专用传送指令IN/OUT
(只能用AX或AL与端口传送信息)
(I/O -& CPU)
长格式:(PORT是端口地址(00~FFH))
执行操作:
PORT )(字)
执行操作:(端口号&255时,先送到DX)
(DX) )(字)
(CPU -& I/O)
功能:将寄存器中内容输出到指定端口。
MOV DX , PORT
  in al,60h;从60h号端口读入一个字节。
  执行时与总线相关的操作:
① CPU通过地址线将地址信息60h发出;
② CPU通过控制线发出端口读命令,选中端口所在的芯片,并通知它,将要从中读取数据;
③ 端口所在的芯片将60h端口中的数据通过数据线送入CPU。
注意:在in和out 指令中,只能使用 ax 或al来存放从端口中读入的数据或要发送到端口中的数据。
I/O 设备的数据传送方式
1、查询方式(程序控制方式)
2 、中断方式
3 、DMA方式(直接存储器存取方式/成组传送方式)
  CPU和内存通过端口与外部设备进行通信。CPU在执行主程序过程中,当需要进行I/O操作时,很难保证输入设备已经准备好了数据,或者是输出设备已经处在可以接收数据的状态。因此,一般要在外部设备准备就绪并且I/O接口已经做好数据传送的情况下,才能进行数据传送,这种传送方式称为查询传送方式。
   查询过程使CPU很容易与不同速度的外设实现速度配合,使接口电路十分简单,适用于较少数据传输情况下使用。但要占用CPU大量时间去查询I/O设备的状态。
中断传输方式
采用中断方式, CPU执行主程序,等待中断的发生。I/O设备与CPU并行操作,进行数据传输的准备工作。当输入设备将数据准备好,或者输出设备空闲时,便通过I/O接口向CPU发申请中断。CPU在每执行完一条指令之后都会检查是否有中断请求,只要满足中断响应条件,CPU就暂停执行当前的程序,转向执行中断处理程序,进行数据传送,等传送完成后,CPU返回到被中断的主程序,继续进行原来的工作。
中断方式:需要保护现场和恢复现场,数据传输由CPU完成。
DMA方式——成组数据传送方式
  主要由硬件DMA控制器实现其传送功能,用于一些高速的I/O设备(比如磁盘),能使I/O设备直接与存储器进行成批数据的快速传送。
  DMA方式:用DMA控制器来控制存储器和I/O设备之间的数据传送时,并不经过CPU,传输过程中CPU不占用总线,CPU处于原地等待。这样,传输时就不需要保存断点等额外操作了。另外,整个控制数据块传送的过程,包括地址增量和计数器减量的操作,都是由硬件控制完成的,因而大大缩短了数据传送的控制时间,提高了整个系统的处理效率。
程序直接控制 I/O 方式
I/O 指令是主机与外设进行通信的最基本途径。DOS 功能调用和BIOS例行程序中的输入/输出功能也是由IN和OUT指令完成的。
例:循环测试某状态寄存器的2位是否为1
AL, STATUS_PORT
AL,DATA_PORT
DATA_PORT, AL
轮流查询几种I/O设备
轮流查询几种I/O设备:
AL, STAT1_BIT
FAR PTR PROC1
AL, STAT2_BIT
FAR PTR PROC2
AL, STAT3_BIT
FAR PTR PROC3
优:由程序安排或修改
设备的优先次序
缺:查询等待浪费CPU大量有效时间
使用I/O指令直接控制输入输出比调用DOS功能或BIOS例行程序效率更高,但其对硬件的依赖性很大,所以一般的程序设计还是尽可能使用DOS或BIOS功能调用。
I/O程序举例: CMOS RAM 芯片
  PC机中有一个CMOS RAM芯片,其有如下特征:
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号单元:
1、将2送入端口70h mov
2、从71h读出2号单元的内容in
CMOS RAM中存储的时间信息
  在CMOS RAM中,存放着当前时间:
  这6个信息的长度都为1个字节,存储了用两个 BCD码表示的两位十进制数,高 4 位的BCD码表示十位,低4 位的BCD 码表示个位。
  比如:b表示14。
读取CMOS RAM的信息
  要读取 CMOS RAM的信息,我们首先要向地址端口70h写入要访问的单元的地址:
out 70h,al
  然后从数据端口71h中取得指定单元中的数据:in al,71h
中断传送方式
  中断:使cpu中止正在执行的程序而转去处理特殊事件的操作。
  中断源:引起中断的事件。CPU最多有256个中断源,这些中断源根据来自CPU的内部还是外部分为两大类:内部中断源和外部中断源。
  外中断(硬中断):
外设的 I/O 请求
可屏蔽中断INTR
电源掉电 / 奇偶错
非屏蔽中断NMI
  所谓不可屏蔽中断是指该中断请求不能通过软件的方式对其屏蔽,一旦出现NMI中断请求,CPU必须立即响应。
  内中断(软中断10H):
INT 指令 / CPU 错(除法错、溢出)
为调试程序设置的中断(t、g命令)
80x86 中断源
(图中引线端标示的数字为分配的终端类型号N(0-255))
  8259A外部有28个引脚。有9片8259A可构成64级中断源。
中断向量表
  各类型(0~0FFH)中断处理程序的入口地址表
中断的条件
(从外设发出中断请求到CPU响应中断,有两个控制条件起决定性作用):
设置CPU中断允许位:
FLAGS 中的IF =
1 的时候允许中断
( STI 开中断)IF =
0的时候禁止中断 ( CLI 关中断)
设置中断屏蔽位:
中断屏蔽寄存器的中断屏蔽位 = 0的时候允许I/O设备请求中断 ,=
1 的时候禁止I/O设备请求中断。
修改中断处理程序
DATAS SEGMENT
DATAS ENDS
STACKS SEGMENT
STACKS ENDS
CODES SEGMENT
ASSUME CS:CODES,DS:DATAS,SS:STACKS
MOV AX,DATAS
MOV AH,35H
MOV AX,SEG FUNCTION
MOV DX,OFFSET FUNCTION
MOV AH,25H
MOV AH,25H
MOV AH,4CH
CODES ENDS
CPU中断过程
1)取中断类型:CPU ← type
2)保护现场:FLAGS、CS、IP入栈
3)IF=0 (关中断),
TF=0(禁止单步中断)
4)计算中断向量地址,取中断向量:(4×N)→ IP,(4×N+2)→ CS
5)转中断处理程序
以上步骤都由硬件完成。采用向量中断的方法,大大加快了中断处理的速度。因为计算机可直接通过中断向量表转向相应的处理程序,而不需要CPU去逐个检测和确定中断原因。
  格式:
n为中断类型码。
  功能:是引发n号中断过程。
  CPU 执行int n过程如下:
1)取中断类型码n;
2)标志寄存器入栈,IF = 0,TF = 0;
3)CS、IP入栈;
4)(IP) = (n*4),(CS) = (n*4+2)。
从此处转去执行n号中断的中断处理程序。
  或者这么理解:
系统功能号送到寄存器AH中
入口参数送到指定的寄存器中
用INT 21H指令执行功能调用
根据出口参数分析功能调用执行情况
键盘输入一个字符到AL中
输出DL寄存器的字符到显示器
DL(存放一个字符)
输出一个以“$”结尾的字符串到显示器
DS:字符串所在的段地址DX:字符串首地址
从键盘输入一个字符串到指定缓冲区
DS:缓冲区所在的段地址DX:缓冲区首地址
缓冲区相应位置
更多请见:
  可见,INT 指令的最终功能和call指令相似,都是调用一段程序。一般情况下,系统将一些具有一定功能的子程序,以中断处理程序的方式提供给应用程序调用。
我们在编程的时候,可以用int指令调用这些子程序,而在子程序中安排iret指令返回。我们将这样的中断处理子程序简称为中断例程。
  IRET指令的执行过程相当于:
中断程序的编写步骤
  中断处理程序的编写与子程序类似,先保护现场,再完成功能,然后恢复现场,最后用IRET指令返回,返回地址是中断发生时紧接着的下一条指令。
中断处理子程序:
  保存寄存器内容,如允许中断嵌套,则开中断 ( STI )
  中断处理功能
  关中断(CLI)
  送中断结束命令( EOI )给中断命令寄存器
  恢复寄存器内容
  IRET中断返回
  1、设置中断向量
  2、设置 CPU 的中断允许位IF
  3、设置设备的中断屏蔽位
  注意:程序员在编程的时候可以调用系统设置好的中断例程,也可以自己编写中断处理程序。 中断类型号0、1、3、4是固定的内部中断,向量2是非屏蔽中断,向量5~31是保留给系统使用的中断,向量32~255则是用户可用的中断。
  编写一个中断处理程序,要求在主程序运行期间,每隔 10秒显示一次字符串‘ bell ’。
.model small
db 'bell',0ah,0dh,'$'
21取向量1ch
push保存原向量
offset ring
21设置新向量
21h;中断屏蔽寄存器
21h,增加定时器中断
DOS系统功能调用
系统功能调用的格式:
① 传送入口参数到指定寄存器中(可选项)
② 功能号送入AH寄存器
INT 21H是一个具有近90个子功能的中断服务程序,这些子功能的编号称为功能号。
INT 21H的功能大致可以分为四个方面,即设备管理、目录管理、文件管理和其他
BIOS和DOS中断
  BIOS是固化在PC机内存地址0FE000开始的8KBROM中的基本输入输出系统的例行程序,它为PC系列的不同微处理器提供了兼容的系统加电自检、引导装入、主要I/O设备的处理程序以及接口控制等功能模块,一般以中断处理程序的形式存在。BIOS可以处理所有的系统中断,如键盘、显示器、磁盘、打印、日期与时间等。BIOS是模块化的结构形式,每个功能模块的入口地址都在中断向量表中,对这些中断调用是通过软中断指令INT来实现的。
  DOS是IBM PC机的磁盘操作系统,由软盘或硬盘提供。它的两个DOS模块IBMBIO.COM和IBMDOS。COM使BIOS使用起来更方便。其}

我要回帖

更多关于 8086汇编语言8254 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信