基本汇编语言程序设计_第1页
基本汇编语言程序设计_第2页
基本汇编语言程序设计_第3页
基本汇编语言程序设计_第4页
基本汇编语言程序设计_第5页
已阅读5页,还剩92页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、第四章基本汇编语言程序设计 1第四章基本汇编语言程序设计第四章 基本汇编语言程序设计4.1顺序程序设计4.2 分支程序设计4.3 循环程序设计4.4 子程序设计4.4.1 过程定义伪指令4.4.2 子程序的参数传递4.4.3 子程序的嵌套、递归与重入4.4.4 子程序的应用 本章要点及习题分析24.1顺序程序设计(e)4.1顺序程序设计指令按程序中的书写顺序逐条执行,称为顺序程序。除非编程解决非常简单的问题,顺序程序并不多见,但是顺序程序往往是复杂程序结构的一部分,如分支结构的一个分支,循环结构的循环体等。返回第四章3例4.1例4.1:设有3个字变量x,y和z,求出三者之和,结果存入字变量w。

2、.model small .startup.stack mov ax,x.data add ax,yXdw 5 add ax,zYdw 6 mov w,axZdw 7 .exit 0Wdw ? end.code4例4.2/1例4.2 设有一个64位数据,将它整个左移8位。123456788765432100qvar0qvar1qvar2qvar3qvar4qvar5qvar6qvar75例4.2/2 .model small .stack .dataQvar dq 1234567887654321h.codemov al,byte ptr qvar6mov byte ptr qvar7,alm

3、ov al,byte ptr qvar5mov byte ptr qvar6,almov al,byte ptr qvar4mov byte ptr qvar5,almov al,byte ptr qvar3mov byte ptr qvar4,al6例4.2/3 mov al,byte ptr qvar2mov byte ptr qvar3,almov al,byte ptr qvar1mov byte ptr qvar2,almov al,byte ptr qvar0mov byte ptr qvar1,almov byte ptr qvar0,012 34 56 78 87 65 43

4、21h34 56 78 87 65 43 21 00h(移位前)(移位后)返回第四章74.2分支程序设计4.2 分支程序设计条件转移指令Jcc和无条件转移指令JMP用于实现程序的分支结构,JMP不测试条件,Jcc可根据条件是否成立决定转移到指定位置或不转移而顺序执行后续指令。由于Jcc不支持条件表达式,而是以当前标志位的状态为条件,故Jcc之前一定要安排设置标志位的指令,如加减法、比较、测试等指令。基本分支类型分为单分支和双分支。8单分支1. 单分支类型 对同一个问题,根据选择的条件不同,单分支结构的流程图有两种画法,对应的程序也有两种编法。如计算AX中的有符号数的绝对值。9单分支 cmp a

5、x,0 jge noneg neg axNoneg: mov result,ax cmp ax,0(教材有误) jnge yesneg jmp doneyesneg: neg axDone: mov result,axAX0 ?求补指令YN保存结果AX0?求补指令YN保存结果JMP10双分支2.双分支程序 两个分支都有语句体,如何选择条件不重要。流程图中分支体的位置就是程序的实际顺序,故分支语句体最后一定要有一条指令,跳过语句体,转移到“后续操作”。条件成立?分支语句体2YN分支语句体1 后 续 操 作 11双分支双分支举例:显示BX的最高位。shl bx,1jc one ;转分支体 mov

6、dl,0 ;分支体1 jmp next;转后续操作One: mov dl,1 ;分支体2next: mov ah,2 ;后续操作 int 21h .分支程序的其他问题有些双分支问题可以先假设一种情况,把双分支改成单分支问题。如上例,先假设BX最高位为0,在分支外准备显示0;如最高位为0,即可直接跳到后续操作;如最高位为1才需要执行分支体。 mov dl,0 shl bx,1 jnc next mov dl,1next:mov ah,2 int 21h12多分支分支的嵌套形成多分支,嵌套形式多种多样。例1:求符号函数 1 当 X0Y= 0 当 X=0 -1 当 X0X0?YNX=0?YNY=-1

7、Y=1Y=0实际是双分支的组合。13多分支例2:判断AL各位的值,D0=1,转移到L0;D1=1,转移到L1;D2=1,转移到L2D0=1分支L0D2=1D1=1分支L1分支L2yyyNNN 也可认为是双分支的组合,但为简化编程,实现左图的分支结构可以在数据段设置转移地址表,如例题4.414多分支 例4.4 使用地址表实现多分支。8个分支的标号分别为disp1,disp2在代码段有:disp1:mov dx,disp2:mov 设disp1的偏移地址为2300h,disp2的偏移地址为2500h。在数据段有:tabel dw disp1,disp2,tabeldisp1disp4disp325

8、00H2300Hdisp5disp6disp7disp802468ACE相对tabel的偏移量15多分支(e)转入分支:按输入的数字转入不同分支 按输入的数字求出分支相对tabel的偏移量:disp1为0,disp2为2,disp3为4,如输入数字2,则偏移量为(2-1)2=2,将求出的偏移量存入bx。 执行指令jmp tabelbx,设bx=02 则IP tabel+bx 即IP 2500H CS:2500H为分支Disp2的入口,CPU即执行分支DISP2返回第四章164.3 循环程序设计4.3 循环程序设计(重复执行的程序段)1.循环程序的组成初始化部分:设置循环条件、次数、初值等。循环

9、体部分:重复执行的代码,含循环条件的修改等。循环控制部分:判断循环条件,决定是否继续。2.两种循环结构1) “先循环、后判断”结构相当于高级语言的“直到型”循环2) “先判断、后循环”结构相当于高级语言的“当型循环”,可实现0次循环。17两种循环结构初 始 化 部 分循 环条件成立?循 环 体 部 分(修改循环条件) NY循 环条件成立?初 始 化 部 分循 环 体 部 分(修改循环条件) YN18循环程序设计3.循环程序设计编写循环程序的关键在于循环的控制。循环次数已知:可用LOOP指令,CX计数。如教材例4.5。循环次数和ZF标志:可用LOOPZ、LOOPNZ指令。如教材例4.6。循环次数

10、未知:通常要采用各类条件转移指令实现循环控制。如教材例4.7,字符串以0结尾;例4.9,字符串以$结尾。19例题分析 循环程序例题分析: 例4.5:计算100个数字之和。 仅用循环次数控制,且循环次数已知,比较简单。 例4.6:确定一个字变量中为1的最低位数。 从最低位向高位依次测试,最多测试16次;测试到某位为1,即可结束程序,测试结果用ZF标志反映,因此可用LOOPE或LOOPZ控制循环(结果非0,退出)。 例4.7:将一个字符串中的所有大写字母改为小写字母,字符串以0结尾。 循环次数未知,应使用条件判断控制循环;循环结构应使用“先判断、后执行”的结构;通常,采用条件判断控制循环时,往往采

11、用“先判断、后执行”的循环结构。 20例题4.6例4.6:确定一个字变量中为1的最低位数。 .startupmov ax,wordX;测试目标送AXmov cx,16;循环计数器置初值mov dl,-1;计位器置初值again:inc dltest ax,1ror ax,1 ;循环指令不影响ZFloope again ;CX0且ZF=1(测试位为0),继续循环je notfound ;退出循环,但0标志成立,没有1mov byteY,dljmp donenotfound:mov byteY,-1;ZF=1,16个位均为0done:.exit 0 end21例题4.7/1例4.7:将一个字符串中

12、的所有大写字母改为小写字母,字符串以0结尾。.dataSteing db xxxxxxxxxxxxxxxxxx,0.code.startupmov bx,offset stringagain: mov al,bx ;取一个字符 or al,al ;是否为结尾符0 jz done ;是,退出循环 22 /2 cmp al,A ;是否为大写AZ jb next cmp al,Z ja next or al,20h ;是,转换为小写字母(使 D5=1) mov bx,al;仍保存在原位置next: inc bx jmp again;继续循环done: .exit 0 end23两重循环结构 4.多重

13、循环:循环程序的嵌套构成多重(多层)循环。最常见的多重循环为两重循环。外循环初始化内循环初始化内层循环体外层循环体内循环结束外循环结束NNYY一个简单延时程序:(双重循环) mov cx,100n_start: mov dx,0ffffhn_loop: dec dx jnz n_loop dec cx jnz n_start内循环控制外循环控制24“冒泡法”排序 例4.8:采用“冒泡法”排序(升序)。 冒泡法从第一个元素开始,依次对相邻的两个元素进行比较,使前一个元素不大于后一个元素;将所有元素比较完之后,最大的元素排到了最后;第一轮比较结束。然后,开始第二轮,除掉最后一个元素,其他元素依上述

14、方法再进行比较,得到次大的元素排在后面;第二轮结束。如此重复,直至完成,就实现了元素从小到大的排序 循环次数已知的双重循环程序。外层循环(轮)的次数为数据个数减1,每一轮外循环的内层循环次数等于剩下的外循环次数。如5个数据,外循环次数=4,第一轮中内循环次数也为4;第一轮作完,还剩下3轮,第二轮中内循环次数等于3,以次类推。 25“冒泡法”排序小数冒泡815163285158163285161583285321615885 1 32 2 85 3 16 4 15 5 8(1轮)4(2轮)3(3轮)2(4轮)1外 循 环 次 数(轮次)序号 数每 轮 内 循 环 次 数4321大数沉底排序示意图

15、须作4轮第1轮26例4.8 排序/1例4.8 对无符号字节数组元素由小到大排序。.dataArray db xx,xx,xx,Count equ ($-array)/(type array).code mov cx,count;CX数组元素个数 dec cx ;元素个数减1为外循环次数outlp:mov dx,cx ;DX内循环次数 mov bx,offset arrayinlp:mov al,bx ;取前一个元素cmp al,bx+1 ;与后一个元素比较jna next ;前一个不大于后一个元素,则不进行交换xchg al,bx+1;否则,进行交换mov bx,al27例4.8 排序/2ne

16、xt:inc bx;下一对元素 dec dx jnz inlp;内循环尾 loop outlp;外循环尾28例4.9 剔除空格程序例4.9:剔除以结尾的字符串中的空格。 双重循环程序:外层循环负责搜索字符串中的空格;内层循环负责剔除搜索到的空格(由于空格后的字符要依次向前移动一个字节,因而也是一个循环结构)。 无论是外层循环,还是内层循环,循环次数都未知,只能用“条件判断”控制循环。 外层循环采用“先判断、后循环”结构;对内层循环而言,由于搜索到空格才进入内循环,所以采用“先循环、后判断”结构。29例4.9/1例4.9:现有一个以$结尾的字符串,要求剔除其中的空格。.datastringdb

17、Let us have a try !,$.code.startupmov dx,offset stringmov ah,9int 21h ;显示原字符串mov al, ;AL空格(ASCII码为20H)mov di,offset string30例4.9/2outlp:cmp byte ptr di,$;外循环,先判断后循环jz done ;为$结束cmp al,di ;检测是否是空格jnz next ;不是空格继续外循环mov si,di ;是空格,进入剔除空格分支inlp:inc si ;该分支是循环程序段mov ah,si ;取空格后的一个字符mov si-1,ah ;向前移动一个字节

18、cmp byte ptr si,$;内循环,先循环后判断jnz inlp31例4.9/3next:inc di ;继续对后续字符进行处理 jmp outlpdone:mov dx,offset string mov ah,9 int 21h ;显示处理后字符串 .exit 0 ;结束 end返回第四章324.4 (目录)子程序设计 4.4 子程序设计 把功能相对独立的程序段单独编写和调试,作为一个相对独立的模块供程序使用,就形成子程序。 使用子程序:简化源程序结构;提高编程效率。 4.4.1 过程定义伪指令 4.4.2 子程序的参数传递 4.4.3 子程序的嵌套递归重入 4.4.4 子程序的应

19、用返回第四章334.4.1 过程定义伪指令(1)4.4.1 过程定义伪指令过程名 PROC NEAR|FAR 过程体 RET(RET N) 过程名 ENDP过程名:符合语法的标识符;同模块唯一性。距离属性:可省略,由汇编程序判断。堆栈使用:平衡。才能保证RET指令弹出的是断点地址。保护现场与恢复现场:子程序用到的寄存器或存储单元,注意:后进先出。注意子程序的规范和格式PUSH AXPUSH BXPUSH CXPUSH DXPOP DXPOP CXPOP BXPOP AX34 关于“距离属性” 关于“距离属性”NEAR属性(段内近调用)的过程只能被相同代码段的其他程序调用FAR属性(段间远调用)

20、的过程可以被相同或不同代码段的程序调用 对简化段定义格式,在微型、小型和紧凑存储模式下,过程的缺省属性为near;在中型、大型和巨型存储模式下,过程的缺省属性为far 对完整段定义格式,过程的缺省属性为near用户可以在过程定义时用near或far改变缺省属性35 子程序规范子程序规范 一个完整的子程序,特别是供其他编程人员使用的子程序,必须附有一个详细说明:子程序名(过程名)子程序功能介绍子程序的入口参数子程序的出口参数子程序内使用的寄存器(存储单元)使用该子程序的范例子程序名:DTOB功能:完成两位十进制数转换成二进制数入口参数:AL存放待转换的两位BCD码出口参数:CL存放转换后的二进制

21、数占用寄存器:BX示例:输入AL=01010110B (56H) 输出CL=00111000B (38H)某子程序的说明36 子程序的常见格式子程序的常见格式;子程序说明;子程序说明subnameproc;具有缺省属性的subname过程push ax;保护寄存器:顺序压入堆栈push bx;ax/bx/cx仅是示例push cx;过程体pop cx;恢复寄存器:逆序弹出堆栈pop bxpop axret;过程返回subnameendp;过程结束37 简单子程序 简单子程序;子程序功能:实现光标回车换行dpcrlfproc ;过程开始push ax ;保护寄存器AX和DXpush dxmov

22、dl,0dh ;显示回车mov ah,2int 21hmov dl,0ah ;显示换行mov ah,2int 21hpop dx ;恢复寄存器DX和AXpop axret ;子程序返回dpcrlfendp ;过程结束38 例4.10:编写子程序(e)例4.10:编写子程序,将AL寄存器内的二进制数用十六进制数显示。8位二进制数,可转换成两位十六进制数。十六进制数ASCII码2#功能调用显示1001B9H1001+0011 000039H(9的ASCII)1010BAH1010+0011 011141H(A的ASCII)注意:对0-9加30H,对A-F加37H,即+30H+07H先转换高4位二进

23、制数,并显示;然后转换低4位并显示。例题410回 4.4394.4.2 子程序的参数传递 4.4.2 子程序的参数传递 主程序和子程序之间通常需要传递参数:入口参数(输入参数):主程序提供给子程序出口参数(输出参数):子程序返回给主程序参数的形式: 数据本身(传值) 数据的地址(传址)传递的方法: 寄存器 变量 堆栈40参数传递方法 1.用寄存器传递参数方便、简单、易行。须要传递的参数较多时不适用。见例题411a。2.用变量传递参数就是用存储器传递参数,当主程序与子程序在同一个模块时,即为共享数据段的变量;不在同一模块,需要用PUBLIC/EXTERN声明。适用与参数较多情况。见例题411b。

24、3.用堆栈传递参数常用方法。用BP访问堆栈段。须格外注意堆栈的平衡。(堆栈示意图)41 堆栈示意图使用堆栈传递参数时堆栈示意图: PUSH 参数1PUSH 参数2PUSH 参数3CALL SUBPRO .EXIT 0SUBPRO PROC PUSH BP MOV BP,SP PUSH AX POP AX POP BP RET (RET 6)SUBPRO ENDPA XB PI P参数3参数2参数1BP=SPBP+2BP+4BP+6BP+8SP(原始)子程序取参数:MOV AX,BP+4(6,8)子程序平衡堆栈:RET 6主程序平衡堆栈: ADD SP,6例题411cSP42例题4.11c/1例

25、题4.11c:计算累加和;用堆栈传递参数;入口参数:数组首地址、数组元素个数;出口参数:AL 累加和 .model small .stack .datacount equ 10array db 12h,25h,0f0h,0a3h,03,68h,71h,0cah,0ffh,90hresult db ?43例题4.11c/2 .code .startup mov ax,offset array push ax ;首地址入栈 mov ax,count push ax ;元素个数入栈 call checksuma add sp,4 ;平衡两个参数占用的堆栈 mov result,al .exit 04

26、4例题4.11c/3checksuma proc push bp mov bp,sp;使BP指向刚进入子程序的堆栈顶, push bx push cx mov bx,bp+6 mov cx,bp+4 xor al,alsuma: add al,bx inc bx loop suma45例题4.11c/4 pop cx pop bx pop bp ret ;可以用RET 4checksuma endp end 46 编写子程序时应注意的问题 编写子程序时应注意的问题: 使用简化的段定义格式时,过程定义在程序中的位置要注意,可以放在1)主程序的最后,即“.EXIT 0”之后,END语句之前;2)放

27、在主程序之前,即“.CODE”之后,“.STARTUP”之前。 使用寄存器传递参数时,带有入口参数的寄存器可以保护,也可以不保护;带有出口参数的寄存器则一定不可保护和恢复;其他与出口参数无关、而子程序中使用的寄存器,子程序开始处应该保护,子程序结束、返回主程序之前应该恢复。回 4.4474.4.3 子程序的嵌套递归重入4.4.3 子程序的嵌套、递归与重入1.子程序的嵌套子程序又调子程序称为子程序的嵌套,嵌套的层数取决于堆栈空间的大小。嵌套子程序的设计和一般子程序完全相同。2.子程序的递归子程序直接或间接地嵌套调用自己,称为递归调用。含有递归调用的子程序称为递归子程序。每次调用时不能破坏以前调用

28、所用的参数及中间结果,因此,调用参数及中间结果一般都放在堆栈中。不可放在固定的寄存器或存储单元中。要控制递归的次数,避免陷入死循环。递归深度受堆栈空间的限制。48 例题4.12例题4.12 用递归子程序求N的阶乘,设N=3。递归次数用N控制,由N=3,子程序共运行4次(主程序调用1次,递归调用3次);入口参数及中间结果都用堆栈保存。注释:1)在进入子程序过程中,不计算阶乘值,只求中间参数。第一次进入,求出中间参数2;第二次进入求出中间参数1;第三次进入求出中间参数0;第四次进入后,由于中间参数以为0,开始执行返回处理。 2)在返回过程中计算阶乘:在过程3中计算1*1=1,在过程2中计算1*2=

29、2,在过程1中计算2*3=6。 3)递归子程序可设计出效率较高的程序,但是编程较难,编出的程序易读性差,使用不多。49 子程序的重入(e)3.子程序的重入子程序被中断后,又被中断服务程序所调用,称为子程序的重入。能够重入的子程序称为可重入子程序。当主机与外设采用中断方式交换信息时,外设的驱动程序应按“可重入原则”设计。虽然重入与递归的概念不同,但递归子程序就是可重入子程序。设计可重入子程序与设计递归子程序的原则是相同的,即参数、中间结果等都用堆栈保存,不能用固定的存储单元或寄存器保存。回 4.4504.4.4 子程序的应用 4.4.4 子程序的应用1)例题4.15 计算有符号数的平均值。 有时

30、进行运算之前,需要符号扩展;对无符号数应进行0扩展。 2)具有局部变量的子程序(截取教材P123部分程序):当某些数据只有子程序自己使用时,可在代码段子程序后面定义数据区。 3)具有多个出口的子程序:有的子程序具有多个出口,根据条件的不同,从不同的出口返回主程序。51例4.15 计算平均值/1例4.15 计算有符号数的平均值。;入口参数用堆栈传递,出口参数用寄存器AX传递。;要计算16位有符号数的和,被加数一定要进行符号扩展。 .model small .stack .dataarray dw 1234,-1234,1,1,-1,32767,-32768,5678,-5678,9000 cou

31、nt equ ($-array)/2 ;数据个数wmed dw ?52 /2 .code .startup mov ax,count push ax ;参数1 mov ax,offset array push ax ;参数2 call mean add sp,4 ;平衡堆栈 mov wmed,ax .exit 053 /3mean proc push bp mov bp,sp push bx push cx push dx push si push di mov bx,bp+4;取参数2:偏移地址 mov cx,bp+6;取参数1:数据个数 xor si,si mov di,si54 /4me

32、an1: mov ax,bx cwd add si,ax adc di,dx inc bx inc bx loop mean1 mov ax,si mov dx,di mov cx,bp+6 dx.ax + di.si di.si55 /5 idiv cx ;求平均值,商在AX,余数在DX pop di pop si pop dx pop cx pop bx pop bp retmean endp end 56避免溢出的方法为了避免有符号二进制数求和过程中溢出,被加数要进行符号扩展,得到倍长数据(大小没有变化),然后求和如数据采用16位二进制数表示,数据个数也采用16位二进制数表示,则最多为2

33、16个数据。如将数据扩展到32位二进制数表示,求和时,就不会出现溢出。考虑极端情况:数据全是215(-32768),共有216个,求和结果是231,32位数据仍然可以表达。对于无符号数,有时也需要得到倍长数据,应采用“0扩展”,即将高位置0,如“MOV DX,0”。57;将AL低4位表达的一位16进制数转换为ASCII码H2ASCprocpush bxmov bx,offset ASCII;BX指向ASCII码表and al,0fh;取得一位16进制数xlat CS:ASCII;换码:ALCS:BXAL,注意数据在代码段CSpop bxret;子程序返回ASCIIdb 30h,31h,32h,

34、33h,34h,35h,36h,37hdb 38h,39h,41h,42h,43h,44h,45h,46hH2ASCendp例题 具有局部变量的子程序 因为数据区与子程序都在代码段,所以利用了换码指令XLAT的另一种助记格式(写出指向缓冲区的变量名,目的是便于指明段超越前缀)。串操作MOVS、LODS和CMPS指令也可以这样使用,以便使用段超越前缀 除采用段超越方法外,子程序与主程序的数据段不同时,我们还可以通过修改DS值实现数据存取;但需要保护和恢复DS寄存器58HTOASCproc;将AL低4位表达的一位16进制数转换为ASCII码and al,0fhcmp al,9jbe htoasc1

35、add al,37h;是0AH0FH,加37Hret;子程序返回htoasc1:add al,30h;是09,加30Hret;子程序返回HTOASCendp例题 具有多个出口的子程序回 4.459例4.13例4.13 编写子程序从键盘输入一个有符号十进制数;并将输入的ASCII码转换为二进制数。输入时,负数用“”引导,正数直接输入或用“”引导子程序用寄存器传递出口参数,主程序调用该子程序输入10个数据将ASCII码转换为二进制数的过程 首先判断输入为正或负数,并用一个寄存器记录 接着输入09数字(ASCII码),并减30H转换为二进制数 然后将前面输入的数值乘10,并与刚输入的数字相加得到新的

36、数值 重复、步,直到输入一个非数字字符结束 负数进行求补,转换成补码;否则直接保存数值60输入和转换流程图输入和转换流程图:A负数求补,正数不变出口参数AX返回1号调用输入字符是+?是-?置负数标志输入下一个0-9之间变成二进制数BX*10+ALBXYNNA输入非数字字符,结束输入61输入数字举例设从键盘输入数字 258:输入顺序:- 2 5 8 CX -1 -1 -1 -1 BX 0 0002 0019H=25 0102H=258数字输入结束后,由于CX为负数标志,再对BX求补。 62程序/1.datacount= 10arraydw count dup(0);预留数据存储空间.code.s

37、tartupmov cx,countmov bx,offset arrayagain:call read;调用子程序输入一个数据mov bx,ax;将出口参数存放缓冲区inc bxinc bxcall dpcrlf ;调用子程序,光标回车换行以便输入下一个数据loop again.exit 0这是主程序63程序/2;输入有符号10进制数的通用子程序;出口参数:AX补码表示的二进制数值read procpush bxpush cxpush dxxor bx,bx;BX保存结果xor cx,cx;CX为正负标志,0为正,1为负mov ah,1;输入一个字符int 21h64程序/3 cmp al,

38、+;是“”,继续输入字符jz read1cmp al,-;是“”,设置1标志jnz read2;非“”和“”,转read2mov cx,-1read1:mov ah,1;继续输入字符int 21hread2:cmp al,0;不是09之间的字符,则输入数据结束jb read3cmp al,9ja read365程序/4 sub al,30h;是09之间的字符,则转换为二进制数;利用移位指令,实现数值乘10:BXBX10shl bx,1mov dx,bxshl bx,1shl bx,1add bx,dxmov ah,0add bx,ax ;已输入数值乘10后,与新输入数值相加jmp read1;

39、继续输入字符66程序/5read3:cmp cx,0jz read4neg bx ;是负数,进行求补read4:mov ax,bx;设置出口参数pop dxpop cxpop bxret ;子程序返回readendpdpcrlfproc ;使光标回车换行的子程序. ;省略dpcrlfendpend67例 4.14例4.14 编写子程序,将二进制数转换为10进制数的ASCII码,并在屏幕上显示一个有符号10进制数。显示时,负数用“”引导,正数直接输出、没有前导字符。子程序的入口参数用共享变量传递,主程序调用该子程序显示10个数据。将二进制数转换为10进制数的ASCII码 首先判断数据是零、正数或

40、负数,是零显示“0”退出 是负数,显示“”,求数据的绝对值; 接着数据除以10,余数加30H转换为ASCII码压入堆栈 重复步,直到余数为0结束 依次从堆栈弹出各位数字,进行显示68显示数字举例 显示数字举例:设AX中数据为-258的补码1.显示负号-。2.求补,AX中得到-258的绝对值。3.258/10,商为25,余数为8,此为个位。 8+30H,入栈。4.25/10,商为2,余数为5,此为十位。 5变ASCII码入栈。5.2/10,商为0,余数为2,此为百位。 2变ASCII码入栈。6.由于商为0,变换结束。7.顺序出栈显示。69程序/1.dataCount = 10Array dw 1

41、234,-1234,0,1,-1,32767,-32768, dw 5678,-78,9000Wtemp dw ? ;共享变量.code.startupmov cx,countmov bx,offset arrayagain:mov ax,bxmov wtemp,ax;将入口参数存入共享变量call write;调用子程序显示一个数据inc bxinc bxcall dpcrlf;便于显示下一个数据loop again.exit 070程序/2 ;显示有符号10进制数的通用子程序 ;入口参数:共享变量wtempwriteprocpush axpush bxpush dxmov ax,wtemp

42、;取出显示数据test ax,ax;判断零、正数或负数jnz write1mov dl,0;是零,显示“0”后退出mov ah,2int 21hjmp write5 ;恢复现场后返回71程序/3write1:jns write2;不是负数,转向数据转换。mov bx,ax ;是负数,显示“”mov dl,-mov ah,2int 21hmov ax,bxneg ax ;求绝对值write2:mov bx,10 ;准备除数push bx ;10压入堆栈,作为退出标志72程序/4write3:cmp ax,0;数据(商)为零jz write4;转向显示sub dx,dx;扩展被除数DX.AXdiv

43、 bx ;数据除以10:DX.AX10add dl,30h ;余数(09)转换为ASCII码push dx ;数据各位先低位后高位压入堆栈jmp write30032h0035h0038h10仍以 258为例25873程序/5write4:pop dx ;数据各位先高位后低位弹出堆栈 cmp dl,10 ;是结束标志10,则退出 je write5 mov ah,2 ;进行显示 int 21h jmp write4write5:pop dx pop bx pop ax ret ;子程序返回writeendp dpcrlfproc ;使光标回车换行的子程序. ;省略dpcrlfendpend74

44、本章要点 本章要点:分支程序设计: 单分支、双分支、多分支 单分支流程图的画法 用转移地址表法实现多分支循环程序设计: 两种循环结构 循环程序的控制方法:计数法、条件判断法 单层循环和双层循环子程序设计: 过程定义伪指令 子程序的参数传递:寄存器、变量、堆栈75习题分析:补充11.将AX中存放的无符号数除以2,如果是奇数,则加1后除以2(单分支)test ax,01h;测试AX最低位jz even ;最低位为0:AX为偶数add ax,1 ;最低位为1:AX为奇数,需要加1even:rcr ax,1;AXAX2;如果采用SHR指令,则不能处理AXFFFFH的特殊情况76补充2/12.判断一元二

45、次方程是否有实根。有,TAG置1; 无,TAG置0。(教材例题4.3:双分支).dataa db ?b db ?c db ?tag db ?.code.startupmov al,bimul almov bx,ax;BX中为b277补充2/2 mov al,aimul cmov cx,4imul cx ;AX中为4ac(DX无有效数据) cmp bx,ax;比较二者大小jge yes ;条件满足?mov tag,0 ;第一分支体:条件不满足,tag0jmp done ;跳过第二个分支体yes:mov tag,1 ;第二分支体:条件满足,tag1done:.exit 0 end78补充3/13.

46、按键盘输入的数字1-8,转8个分支(显示不同的信息)。(同教材例题4.4,但显示的信息不同)分析过程见课件4.2节的“多分支部分” .datamsg db Input number(18):,0dh,0ah,$Msg1 db Chapter 1 : .,0dh,0ah,$msg2 db Chapter 2 : .,0dh,0ah,$.msg8 db Chapter 8 : . ,0dh,0ah,$table dw disp1,disp2,disp3,disp4 dw disp5,disp6,disp7,disp8;取得各个标号的偏移地址79补充3/2 start1:mov dx,offset

47、msg;提示输入数字 mov ah,9 int 21h mov ah,1;等待按键 int 21h cmp al,1;数字 8? ja start1 and ax,000fh;将ASCII码转换成数字80补充3/3 dec ax shl ax,1;等效于add ax,ax mov bx,ax jmp tablebx ;(段内)间接转移:IPtable+bxstart2:mov ah,9 int 21h .exit 0disp1: mov dx,offset msg1;处理程序1 jmp start2Disp2:. end81习题4.4 习题分析4.4 编写一个程序,把从键盘输入的一个小写字母用

48、大写字母显示出来。 框图:(省略输入字符的判断:简单的顺序程序)1号调用:输入字符ALAL-20H2号调用:显示字符结 束824.54.5 已知用于LED数码管显示的代码表为: LEDTABEL DB 0C0H,0F9H(共16项数据)依次表示09,AF这16个数码的显示代码,编写一个程序实现将lednum中的一个数字转换成对应的LED显示代码。(查表程序)BX代码表首地址ALlednum执行指令XLATAL中即为所求的显示代码834.84.8 如果在例题4.4的tabel中依次添入msg1msg8,程序应该如何修改?(Tabel dw msg1,.) mov bx,ax mov bx,ax

49、jmp tabelbx mov dx,tabelbxStart2: mov ah,9 mov ah,9 int 21h int 21h .exit 0 .exit 0 end 程序变得更加简单。取显示信息 偏移地址取转移地 址送IP844.94.9 编制一个程序,将变量BUFX、BUFY中较大者送入BUFZ;若两者相等,则把其中之一送入BUFZ中。设变量为无符号8位数。ALBUFXCMP AL,BUFYAL小于BUFY?ALBUFYBUFZALYNDONE:JAE DONE854.104.10 设变量bufX为有符号数,编程将其符号状态保存在singX,如X大于等于0,保存0;如X小于0,保存

50、-1。 该题为一个可以演变成单分支的双分支结构:测试bufX符号0-1singX0singXnextY0singX测试bufX符号0-1singXnextY864.114.11 X、Y、Z是三个有符号16位数(教材误印为16进制数),编写程序: 1)三个数都不相等,显示0; 2)有两个数相等,显示1; 3)三个数都相等,显示2。 三个数比较,应有5种情况: X=Y=Z 显示2 X=YZ 显示1 X=ZY 显示1 XY=Z 显示1 XYZ 显示0 编程时必须要考虑到所有5种情况。874.11框图X-ZX=Y=ZX=YZXY=ZX=ZYZF=1X-YX-ZY-ZXYZZF=1ZF=1ZF=0ZF=0ZF=1ZF=0884.134.13

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论