发展部件技术分享 http://blog.sciencenet.cn/u/求新 研究方向:数据库、MIS,教育部教指委计算机分委会专家工作组成员

博文

汇编语言实验园地_10

已有 10111 次阅读 2009-2-16 12:30 |个人分类:生活点滴|系统分类:教学心得|关键词:学者| 实验, 程序设计, 汇编

                                                          实验9程序与实验10实验课题
                                    实验10  利用子程序进行串处理及有关日期的程序设计
一、实验内容:利用子程序结构设计从串中查找一个字符的所有位置、查找一个字符串。宏汇编程序设计。
二、实验目的:1. 学习结构化程序设计方法。
              2. 如何在一个串中查找到一个字符的所有位置。
              3. 如何在一个串中查找到一个另一个字符串。
              4. 认识宏的概念,学习宏汇编程序设计方法
三、实验题目
1. 要求自行设定二个字类型的串STRING1与STRING2的内容,用程序对这二个串进行比较,如果相等,0送BX,否则,0FFFFH送BX。设串长为COUNT。最后分别以16进制形式显示BX、STRING1与STRING2的内容。
思考:本题如果不借助串比较指令来做,需要怎样设计?要考虑一个串和另一个串不相同但前面有部分字符相同的情况。
以下两题为实验8第1题利用子程序结构求解的设计参考。
2. 已知程序段如下,将它补充完整,使能将结果(BX的值)以16进制形式在屏幕上显示,根据显示情况分析说明其功能是什么?要求将16进制显示程序段利用子程序进行设计。
DATA     SEGMENT
          BUF  DB ‘AABAAAAABBCD‘
          COUNT  EQU  $-BUF
DATA     ENDS
……
          MOV    AL, ‘A‘
          MOV     DI,OFFSET BUF
          MOV     CX,COUNT
          DEC      DI
NEXT:    INC       DI
          CMP    AL,[DI]
          LOOPE    NEXT
MOV    BX,DI
          JNZ   EXIT
          MOV  BX,0FFFFH  ;当ZF=1,CX=0时退出循环
EXIT:…….

3. 对在STRING中搜索A的程序段进行补充设计,要求对设计加详细注释。要求自行设定一个长度COUNT的字节类型的串STRING的内容,用循环程序对这个串进行搜索,如果搜索到字节类型数据A,显示当前位置(字长)。STRING、COUNT、A的内容自行设计。

        LEA   DI,STRING
        MOV  AL,A
        MOV  CX,COUNT
        CLD
        REPNE  SCASB
        JZ     OK
        ……
    OK: ……

4. 在一个串中查找一个字符,显示查到该字符的次数。

5 用串指令在一个串中查找一个字符,显示所有查到位置的地址。如果没有欲查字符,显示“-1”。

6.在一个串中查找另一串,如果找到,将查到串的首地址存到DI中。

7.求编写显示系统的当前日期和时间的程序。要求程序运行时显示的信息格式为:
Current date is 10-30-2008. Current time is 10:23:26.12
相关的DOS功能调用:
【获取系统当前日期】
调用指令:INT 21H
功 能 号:2AH
入口参数:无
出口参数:CX = 年(范围1980~2099)
DH = 月(1~12)
DL = 日
【获取系统当前时间】
调用指令:INT 21H
功 能 号:2CH
入口参数:无
出口参数:  CH = 小时(0~23)
CL = 分(0~59)
DH = 秒(0~59)
DL = 百分之一秒(0~99)
8. 设计一个万年历程序。已知2008年1月1日为星期二,求2008年之后21世纪的某年某月某日是星期几?不考虑输入错误。
分析:假设通过键盘分别输入公元年份(输入末二位)、月份(二位)、日期(二位),可以利用前面的子程序分别变成二进制数。再计算输入日期与2008年1月1日之间相差日数X,将X除以7的余数加2就代表星期几,7代表星期日,1代表星期1,……。而要计算相差日数X,必须考虑闰年问题:4年一闰、百年不闰、400年闰。非闰年365天,2月份28天;闰年366天, 2月份29天。可以先分析年份之差,对每一年判断是否闰年,再加366或365;再分析月份之差,求出所求年内距离1月1日的天数。为了能用一个程序计算各个月的情况,设计一个表:ruler=31,28,31,30,31,30,31,31,30,31,30,31,每一个值代表一个月是大月还是小月,1表示31天,0表示30天,利用间址查表求天数。2月单独计算。为求程序清晰,分别设计了分析闰年、月份二个子程序,在求解星期几的程序中调用。


实验10参考程序段

1. 用循环指令在一个串中查找一个字符,第一次查到该字符时将地址放在DI中。
MOV  AX,DATA
          MOV  DS,AX
          MOV    AL, 'A'
          MOV    DI,OFFSET BUF
          MOV    DX,0
          MOV    CX,COUNT
          DEC    DI
NEXT:     INC    DI
          CMP    AL,[DI]
           JZ    NEXT1
          LOOP   NEXT
NEXT1:  

2. 用串指令在一个串中查找一个字符,查到第一个时将位置放在DI中。
MOV  AX,DATA
          MOV    DS,AX
          MOV    ES,AX
          MOV    AL, 'A'
          MOV    DI,OFFSET BUF
          MOV    CX,COUNT
          REPNE  SCASB
          JNZ     EXIT
          DEC    DI         ;找到的存放地址放在DI中
3.在DAT1串中查找ADD2串的第1个字符(串长COUNT2),如果找到,将剩余串的首地址存到ADD1中,剩余串长度存到ADD2中。
 MOV   AX,DATA      
       MOV   DS,AX
       MOV   ES,AX
       MOV   ADD1,OFFSET DAT1   ;立即数传存储器
       MOV   AL,X           ;取欲查之字符串第1个字符
       MOV   ADD2,COUNT2
       CLD
BACK1: MOV   DI,ADD1       ;取欲查字串首地址
       MOV   CX,ADD2       ;取欲查字串长度
       REPNE  SCASB        ;查找
       MOV   ADD1,DI       ;保存剩余串首地址
       MOV   ADD2,CX       ;保存剩余串长度
4.求系统的当前日期和时间分别放在DX与CX中的程序。假使在数据区FNAME保存一个文件的名字。其中DX 中存年月日的格式:  0-4位:日,5-8位:月,9-15位:年份-1980。CX中所存时间的格式:   0-4位:秒/2,5-10位:分,11-15位:时
       MOV  DX,  OFFSET  FNAME
       MOV  AL, 2                          ; 读写方式
       MOV  AH, 3DH                       ;打开文件
       INT   21H
       MOV  BX, AX
       MOV  AH,  57H                      ; 读改日期
       MOV  AL,0                         ;0 表示读出时间,1表示改写时间
       INT  21H
       MOV DI,CX
5.求以十进制方式显示DX(日期)内容的宏。
AXTOBCD1  MACRO
      PUSH SI
      PUSH DI
      PUSH CX
      MOV SI,DX
;DX 中存年月日  0-4位:日,5-8位:月,9-15位:年份-1980
;保存CX中所存时间   0-4位:秒/2,5-10位:分,11-15位:时
      MOV CL,7              ;年
      ROL SI,CL
      MOV DX,SI
      AND DX,7FH
      ADD DX,1980
      AXTOBCD DX
      MOV DL,'.'
      MOV AH,2
      INT 21H
      MOV CL,4              ;月
      ROL SI,CL
      MOV DX,SI
      AND DX,0FH
      AXTOBCD DX
      MOV DL,'.'
      MOV AH,2
      INT 21H
      MOV CL,5              ;日
      ROL SI,CL
      MOV DX,SI
      AND DX,1FH
      AXTOBCD DX
      MOV DL,'.'
      MOV AH,2
      INT 21H
      POP CX
      POP DI
      POP SI
ENDM          
6.求以十进制方式显示DI(时间)内容的宏。
AXTOBCD2  MACRO
      PUSH SI
      PUSH DI
      PUSH CX
     MOV CL,5              ;时
      ROL DI,CL
      MOV DX,DI
      AND DX,1FH
      AXTOBCD DX
      MOV DL,'.'
      MOV AH,2
      INT 21H
      MOV CL,6              ;分
      ROL DI,CL
      MOV DX,DI
      AND DX,3FH
      AXTOBCD DX
      MOV DL,'.'
      MOV AH,2
      INT 21H
      MOV CL,5              ;秒
      ROL DI,CL
      MOV DX,DI
      AND DX,1FH
      SHL DX,1
      AXTOBCD DX
      MOV DL,'.'
      MOV AH,2
      INT 21H

      POP CX
      POP DI
      POP SI
ENDM          
    
7. 求从键盘输入二个十进制数字变成二进制数子程序
;子程序名:IMPOR
;程序功能:从键盘输入二个十进制数字变成二进制数
;入口参数:
;出口参数: 二进制数:BX
;使用寄存器:AX
IMPOR  PROC
      MOV   AH,1H
      INT   21H            ;键盘输入1个字符,不考虑输入错
      SUB   AL,30H
      MOV   BL,10      
      MUL   BL
      MOV   BL,AL
      MOV   AH,01H
      INT   21H                       ;键盘输入第二个数字
      SUB   AL,30H
      ADD   AL,BL
EXIT: MOV   AH,0
      MOV   BX,AX
      RET
IMPOR  ENDP

8. 求AX中数表示的某一年份的日数的子程序
;子程序名:LEAPY
;程序功能:求AX中数表示的年份的日数
;入口参数:年份:CX
;出口参数:该年日数:AX
;使用寄存器:DX、BX
LEAPY  PROC
      MOV  AX,CX   ;保存DI到AX
      MOV DX,0
      MOV BX,4
      DIV  BX
      CMP  DX,0
      JNZ  DISP3    ;不能整除4,不是闰年
      MOV AX, CX
      MOV BX,100
      DIV  BX
      CMP DX,0
      JNZ  DISP4    ;不能整除100,是闰年
      MOV AX, CX
      MOV BX,400
      DIV  BX
      CMP DX,0
      JZ DISP4    ;能整除400,是闰年
DISP3: MOV AX,365
      MOV BYTE PTR Y,0     ;置非闰年标志
      JMP  EXIT1
DISP4: MOV AX,366
      MOV BYTE PTR Y,1     ;置闰年标志
EXIT1: RET
LEAPY  ENDP

                   实验9部分参考程序
1、在数据区中有如下定义,要求首先将有关常量存放到数据区BUF中,再编一个循环程序,使依次以10进制形式显示各变量的值(不要求显示变量名)。
     NUM1 EQU 25*4-50 
     NUM2 EQU NUM1/7 
     VAR1 DB 1,2,3,4,5
     VAR2 DB '12345'
     NUM4 EQU VAR2-VAR1 
     NUM5 EQU 0FH
     BUF   DB  7 DUP(?)
;程序1解:以十进制形式显示各数(循环方式)
DATA  SEGMENT
     NUM1 EQU 25*4-50 
     NUM2 EQU NUM1/7 
     VAR1 DB 1,2,3,4,5
     VAR2 DB '12345'
     NUM4 EQU VAR2-VAR1 
     NUM5 EQU 0FH
     BUF   DB  7 DUP(?)
     D1    DB  ?,?,?,?,?,?   ;根据子程序要求建立显示数据区
DATA  ENDS
STACK  SEGMENT  STACK
        DB  200   DUP(0)
STACK  ENDS
CODE  SEGMENT
       ASSUME   DS:DATA,SS:STACK,CS:CODE
START:MOV  AX,DATA
      MOV  DS,AX
      MOV  SI,OFFSET BUF       ;将有关数据放BUF数据区使方便循环求解
      MOV  [SI],BYTE PTR NUM1
      INC  SI
      MOV  [SI],BYTE PTR NUM2
      INC  SI
      MOV  AL,VAR1
      MOV  [SI],AL
      INC  SI
      MOV  AL,VAR2
      MOV  [SI],AL
      INC  SI
      MOV  [SI],BYTE PTR NUM4
      INC  SI
      MOV  [SI],BYTE PTR NUM5

      MOV  SI,OFFSET BUF     ;准备从BUF数据区依次取数显示
      MOV  DI,OFFSET D1+5   ;根据子程序要求将DI指向显示数据区尾部
      MOV  BP,6               ;共计显示6个数据
NEXT: MOV  AH,0         ;根据子程序要求将欲显示数据取到AX中
      MOV  AL,[SI]   ;显示数据为字节类型,而AX为字类型
      CALL P1        ;调用显示子程序
      INC  SI
      DEC  BP       ;共显示6个数据,由BP决定循环次数
      JNZ  NEXT
      MOV  AH,4CH
INT  21H

;子程序名:p1
;功能: 以十进制形式显示任意字
;输入参数: 显示字在AX中。要求在数据区建5字节的显示数据区,
;要求用DI指向其尾部。
;输出参数:
;*  *  *  *  *  *  *
P1   PROC
     MOV    BX,10         ;准备除以10
CHANGE10: MOV    DX,0  ;将除数的高16位(在DX中)清0,DX存放余数
     DIV    BX             ;DX,AX除以BX  (BX=10)
     ADD    DL,30H             ;余数变为ASCII码值
     MOV    BYTE PTR[DI],DL    ;存储十进制数
     DEC    DI                 ;到上一单元
     CMP    AX,0               ;是否为0?
     JNZ    CHANGE10           ;不为0转CHANGE10
     MOV    CX,5               ;准备连续显示5个数
CHANGE11:MOV   DL,BYTE PTR[DI] ;取出存放在BUF中的十进制数到DL供显示
     MOV    AH,2           ;显示1个字符
     INT    21H
     INC    DI
     LOOP   CHANGE11
     RET
P1  ENDP
CODE  ENDS
       END  START


2. 利用子程序结构将八位无符号二进制数转换为十进制数的ASCII码并显示。
DATA  SEGMENT
    BIN  DB  11111111B
    ASC  DB  3 DUP(?),"$"
DATA  ENDS
STACK  SEGMENT  STACK
    DB  200   DUP(0)
STACK  ENDS
CODE  SEGMENT
      ASSUME   DS:DATA,SS:STACK,CS:CODE
START:MOV  AX,DATA    ;给数据段寄存器DS赋值
    MOV  DS,AX
    MOV  AL,BIN
    MOV  BX,OFFSET ASC
    ADD  BX,2       ;指向存放ASCII码值结果的存贮单元末地址
    CALL  TRANSFORM     ;转子程序实现转换
    LEA  DX,ASC
    MOV  AH,9
    INT  21H
    MOV  AH,4CH    ;中断返回DOS状态
    INT  21H
;*  *  *  *  *  *  *
;子程序名:TRANSFORM
;功能:将八位无符号二进制数转换为十进制数ASCII码
;入口参数:八位二进制数=>AL
;         存放ASCII码值末地址=>BX
;出口参数:在ASC开始的存贮单元中
;*  *  *  *  *  *  *
TRANSFORM  PROC  NEAR
    PUSH  CX
    PUSH  DX
    MOV  CX,3
    MOV  DL,10
    AGAIN:MOV  AH,0   
    DIV  DL
    ADD  AH,30H
    MOV  [BX],AH
    DEC BX
    LOOP  AGAIN
    POP DX
    POP CX
    RET
TRANSFORM  ENDP
CODE  ENDS
END START
说明:转换子程序中用到了AX(AH,AL),BX,CX,DX(DH,DL)四个16位的寄存器。为什么进入子程序后,只对CX,DX寄存器作了压栈保护,而对AX,BX 寄存器没有呢?原因在于:AX,BX是用于参数传递目的的两个寄存器,而CX,DX却不是。进入子程序中压栈保护所用的寄存器一般指不用于参数传递目的的寄存器,所以对CX,DX作了压栈保护,而对AX,BX却没有。
另外,此题也可不用除法指令,而采用一连串的相减来实现,思路为:八位二进制数能够减去100的次数,就是转换的十进制数百位;同理,从余下的二进制数中再减去10的次数,便是十进制的十位;最后余下的就是十进制数个位。有兴趣的同学可自己试着实现。
结合上题与本题可以总结子程序的格式,子程序所放的位置,子程序的调用方法。
调用子程序命令为:
CALL
子程序以  <子程序名> PROC  开始。
例如:
TRANSFORM  PROC
后面的  NEAR  表示在同一段内,可以省略,否则要用FAR。子程序结尾为:
RET
<子程序名>  ENDP
例如,本子程序结尾:
RET
TRANSFORM  ENDP
每个子程序开始应当给出说明:子程序名、功能、入口参数、出口参数、使用寄存器。既便于自己理解,也方便之后其他程序调用。使用寄存器只列举在本程序中使用了但未在子程序中保护且不是入口参数和出口参数中声明了的寄存器。
子程序用CALL命令调用,格式:  CALL  <子程序名>
子程序不能在代码中随意放,初学建议放在MOV  AH,4CH   和    INT  21H 这二句之后。
3. 用子程序形式求解实验7第3题:在内存的源数据区SOURCE处有若干个ASCII码字符,要求将其中的英文大写字母变换为小写字母,其它字符不变换,并存放到结果数据区DEST处。
分析:英文大写字母‘A’—‘Z’,ASCII码值为41H—5AH。相应的小写字母为‘a’—‘z’,ASCII码值为61H—7AH。英文大写字母要转换为相应的小写字母只要ASCII码值加20H即可。
例如:‘B’─‘b’   42H+20H=62H
我们将转换这一过程用子程序TRANBL来实现,参数传递借助存贮单元,其算法流程图如右图所示。
完整程序如下所示:
DATA  SEGMENT
SOURCE  DB 'BEIjin2008OLYMPIC'
COUNT  EQU  $-SOURCE  ;字符个数
DEST  DB  COUNT DUP(?)
DATA  ENDS
CODE  SEGMENT
     ASSUME  CS:CODE,DS:DATA
START:MOV  AX,DATA      
     MOV  DS,AX
     CALL  TRANBL
     MOV  AH,4CH
     INT  21H
;*  *  *  *  *  *  *
;子程序名:TRANBL
;功能:大写字母转换为小写字母
;输入参数:数据区SOURCE处,字符个数由COUNT指明
;输出参数: 输出数在数据区DEST处
;*  *  *  *  *  *  *
TRANBL  PROC  NEAR
     PUSH  AX
     PUSH  CX
     PUSH  SI
     PUSH  DI
     MOV  SI, OFFSET SOURCE
     MOV  DI, OFFSET DEST
     MOV  CX,COUNT
     AGAIN:MOV  AL,[SI]
     CMP  AL,41H          ;与大写字母‘A’比较
     JB  NEXT
     CMP  AL,5AH        ;与大写字母‘Z’比较
     JA  NEXT
     ADD  AL,20H         ;转换
     NEXT:MOV  [DI],AL
     INC  SI
     INC  DI
     LOOP  AGAIN
     POP  DI
     POP  SI
     POP  CX
     POP  AX
     RET
TRANBL  ENDP
CODE  ENDS
END  START

6. 求将一个16位二进制数转换为任意P(0到19)进制数,P从键盘输入并显示(超过9的数字按:10用A,11用B,……,19用I表示)。
分析:在前面例子中已经给出了16位二进制数转换为十进制、十六进制的例子,方法都是依次除进制数、取余、倒写。转换为任意P进制数的问题,只是将这些例题中的除数要更换为P的具体值。可以将这些转换程序改写成子程序,子程序中要用到寄存器DI、AX,使用寄存器不多,故设计P从主程序经BX带入、二进制数从主程序经SI带入。为具有实用价值,本题所涉及的P值及二进制数均从键盘输入,输入的都是ASCII码,需要变成二进制数,该工作分别设计子程序完成。
程序设计如下:
DATA  SEGMENT 
     CHAR_BUF  DB    6                           ;缓冲区最大长度
            DB    ?                           ;实际输入字符个数
            DB    6  DUP(0)                   ;输入缓冲区
      BUF  DB   17  DUP(0)                   ;输出缓冲区
     CLEW1  DB   'PLEASE  INPUT  ALGORI  X(0....65535) :', '$'       ;提示信息1
     CLEW2  DB   0DH,0AH,'PLEASE  INPUT  CARRY  P(0....19) :', '$'   ;提示信息2
     ENTER1  DB   0DH,0AH, '$'                                      ;回车换行
DATA  ENDS
STACK  SEGMENT  STACK
     DB 200 DUP(?)
STACK ENDS  
CODE  SEGMENT 
       ASSUME   DS:DATA,CS:CODE,SS:STACK 
START:MOV  AX,DATA
      MOV  DS,AX
      MOV  DX,OFFSET CLEW1                 ;提示信息1
      MOV  AH,9
      INT  21H
      CALL  IMPOR1       ;输入二进制数子程序
      MOV  DX,OFFSET CLEW2                 ;提示信息2
      MOV  AH,9
      INT   21H
      CALL  IMPOR2      ;输入进制数P子程序
      MOV  DX,OFFSET ENTER1               ;回车换行
      MOV  AH,9    
      INT   21H
      MOV  DI, OFFSET  BUF  ;根据VERSIO入口要求使指针DI指向BUF缓冲区
      ADD    DI,17       ;假定BUF从0起准备17个单元,DI指向BUF尾
      MOV    BYTE PTR [DI],"$"      ; 所有余数的最后加“$”
      CALL  VERSIO      ;转换并显示子程序
      MOV  AH,4CH
      INT   21H

;子程序名:IMPOR1  
;程序功能:从键盘输入至多5个十进制数字变成二进制数(0到65535),回车表示输完
;入口参数:缓冲区首址:CHAR_BUF
;出口参数: 从键盘输入的数:SI
;使用寄存器:DI,DX,BX,CX,AX
IMPOR1  PROC NEAR
INPUT:    MOV   DX,OFFSET CHAR_BUF
    MOV   AH,0AH
    INT   21H                       ;键盘输入字符串
    MOV   DI,OFFSET CHAR_BUF
    MOV   CL,[DI+1]                  ;取实际输入串长度
    MOV   CH,0
    MOV   AX,0                    ;准备存放结果
    MOV   BX,10                   ;乘10的乘数
    MOV   DH,0                    ;清DX高8位
CHANGE:   MUL   BX                        ;(AX)乘10
    MOV   DL,[DI+2]                 ;取一个字符
    SUB   DL,30H             ;变成数字
    ADD   AX,DX
    INC   DI
    LOOP  CHANGE
    MOV  SI,AX                ;带出结果
    RET
IMPOR1  ENDP

;子程序名:IMPOR2 
;程序功能:从键盘输入至多二个十进制数字变成进制数P(2……19)
;入口参数:
;出口参数: 进制数P:BX
;使用寄存器:AX
IMPOR2  PROC NEAR
    MOV   AH,01H
    INT   21H            ;键盘输入1个字符,不考虑输入错
    SUB   AL,30H
    CMP   AL,1          ;如果第1个字符输入大于1,表示只1位
    JA    EXIT
    MOV   BL,10      
    MUL   BL
    MOV   BL,AL
    MOV   AH,01H
    INT   21H                       ;键盘输入第二个数字
    SUB   AL,30H
    ADD   AL,BL
EXIT:     MOV   AH,0
    MOV   BX,AX
     RET
IMPOR2  ENDP

;子程序名:VERSIO     
;程序功能:将16 位二进制数转换为P进制数并显示
;入口参数:数组BUF首址: DI,进制数P:BX,存放二进制数:SI
;出口参数:
;使用寄存器:AX
VERSIO PROC NEAR    
     MOV    AX,SI
CHANGE1: DEC    DI       ;指针向前移
     DIV     BL      ;(AX)除以P余数在AH中
     ADD    AH,30H       ;余数变为对应的ASCII码值
     CMP    AH,39H      ;是否是‘A’-‘F’
     JBE     NEXT
     ADD    AH,7         ;如果是‘A’-‘F’,再加7
NEXT:     MOV    BYTE PTR[DI],AH      ;保存转换后的十六进制数结果
     MOV    AH,0
     CMP    AL,0            ;判断商是否为0?
     JNZ    CHANGE1             ;不为0转CHANGE1 
     MOV    DX,DI
     MOV    AH,9
     INT    21H
       RET
VERSIO ENDP
  CODE  ENDS
     END  START
7. 求一个小于65535的整数N的因数分解,即将一个整数分解成质数的乘积。
分析:因数分解的方法是从I=2起,看能否整除N,如果能,则I为一个质数,记下整除后的数代换N并继续整除到不能整除为止。再将I加1后继续,……,直到I大于被除数为止。
;设数据区如下,求分解为质数放在PRIMEN中并显示。
DATA  SEGMENT 
     M1      DW  10920
     M2      DW  0
     PRIMEN DW 10 DUP(0)
     M      DB  0 
     d      db  5 dup(0)  
DATA  ENDS
STACK  SEGMENT  STACK
     DB 200 DUP(?)
STACK ENDS  
CODE  SEGMENT 
       ASSUME   DS:DATA,CS:CODE,SS:STACK 
START:MOV  AX,DATA
      MOV  DS,AX
      CALL PRIME         ;转分解质数子程序
      LEA  DI,D+5        ;指向显示数据区尾地址
      LEA  SI,PRIMEN       ;指向质数数据区首地址
      MOV  CL,M         ;欲显示的质数个数
      MOV  CH,0
LOOP1:MOV  AX,[SI]      ;取显示数据
      CALL P1
      ADD  SI,2
      LOOP LOOP1
     
      MOV  AH,4CH
      INT  21H
;子程序名:PRIME
;程序功能:将字数据分解为质数
;入口参数:字数据:变量M1
;出口参数: 质数数组:PRIMEN
;           数组元素个数:M
;使用寄存器:AX
PRIME  PROC
    MOV   DI,OFFSET PRIMEN
    MOV   AX,M1
    MOV   M2,AX
    MOV   CL,0
DISP1:    MOV   BX,2          ;从2开始分析质数
DISP2:    MOV   AX,M2
    MOV   DX,0
    DIV   BX
    CMP   DX,0         ;余数是否为0?
    JNE   DISP4
    MOV   [DI],BX         ;保存一个质数
    ADD   DI,2         ;准备存放下一个质数
    MOV   M2,AX
    INC   CL
DISP3:    MOV   DX,0
    DIV   BX
    CMP   DX,0         ;继续取出同一个质数不再保存
    JNE   DISP4
    MOV   M2,AX
    JMP   DISP3
DISP4:    CMP   BX,M2
    JA    EXIT
    INC   BX
    JMP   DISP2
EXIT:     MOV  M,CL
RET
PRIME  ENDP
;子程序名:p1
;功能: 以十进制形式显示任意字
;输入参数: 显示字在AX中。要求在数据区建5字节的显示数据区,
;要求用DI指向其尾部。
;输出参数:
;*  *  *  *  *  *  *
P1   PROC
     PUSH  BX
PUSH  DX
PUSH  DI
PUSH  CX
MOV    BX,10         ;准备除以10
CHANGE10: MOV    DX,0  ;将除数的高16位(在DX中)清0,DX存放余数
     DIV    BX             ;DX,AX除以BX  (BX=10)
     ADD    DL,30H             ;余数变为ASCII码值
     MOV    BYTE PTR[DI],DL    ;存储十进制数
     DEC    DI                 ;到上一单元
     CMP    AX,0               ;是否为0?
     JNZ    CHANGE10           ;不为0转CHANGE10
     MOV    CX,5               ;准备连续显示5个数
CHANGE11:MOV   DL,BYTE PTR[DI] ;取出存放在BUF中的十进制数到DL供显示
     MOV    AH,2           ;显示1个字符
     INT    21H
     INC    DI
     LOOP   CHANGE11
     POP    CX
     POP    DI
     POP    DX
     POP    BX
   RET
P1  ENDP

    CODE  ENDS
END  START
8. 计算:X的平方根与有的平方根的和
其中x、y为整型数据,分别存放在XBUF和YBUF单元中,所得结果f存放在FBUF中。要求将FBUF中数据在屏幕上显示。
分析:求一个整数平方根可以通过将该整数依次减去1、3、5、7…(n-1)的奇数,所够减的次数即为平方根值。
例如求16的平方根时可这样进行:
16-1=15   够减1次
15-3=12   够减2次
12-5=7    够减3次
7-7=0     够减4次
所以16=4
求平方根的过程我们用子程序SQROOT来实现,参数的传递借助堆栈。求平方根子程序算法流程图如图所示。

DATA  SEGMENT
    XBUF  DW  81
    YBUF  DW  100
    FBUF  DW  ?
DATA  ENDS
STACK  SEGMENT
    TOP  DW  20 DUP(?)
STACK  ENDS
CODE  SEGMENT
ASSUME  CS:CODE,DS:DATA,SS:STACK
START:MOV  AX,DATA        ;给DS赋值
        MOV  DS,AX
        MOV  SI,XBUF
        CALL SQROOT
        MOV  AX,SI
        MOV  SI,YBUF
        CALL SQROOT
        ADD  SI,AX
        CALL DISPLAY16
        MOV  AH,4CH
        INT  21H
;*  *  *  *  *  *  *
;子程序名:SQROOT
;功能:求平方根运算
;输入参数:SI
;输出参数:SI
;*  *  *  *  *  *  *
SQROOT  PROC  NEAR
        PUSH  AX
        PUSH  BX
        PUSH  CX
        MOV  AX,SI    ;取被开方数
        SUB  CX,CX        ;CX置0
AGAIN:MOV  BX,CX       ;下面三条指令使BX=2*CX+1
        ADD  BX,BX
        INC  BX
        SUB  AX,BX
        JC  OVER            ;不够减转OVER
        INC  CX
        JMP  AGAIN
OVER:MOV  SI,CX    ;平方根放回原堆栈区
        POP  CX
        POP  BX
        POP  AX
        RET
SQROOT  ENDP

;子程序名:DISPLAY16
;功能:以移位方式显示16进制数
;占用寄存器:BX,CL,AX,DX
;输入参数:要显示数据在SI中
;输出参数:无

DISPLAY16   PROC
         MOV    BX,4         ;每个字显示4个16进制字符
CHANGE10:      MOV    CL,4         ;准备左移4位(除以16)
         ROL    SI,CL            ;SI循环移4位
         MOV    DX,SI            ;转存到DX
         AND    DX,0FH            ;清高12位
         ADD    DL,30H       ;一个16进制数变为ASCII码值
         CMP    DL,3AH       ;是否小于10?
         JB     CHANGE12       ;如果小于10转显示
         ADD    DL,7           ;否则为A到F之间数,加7
CHANGE12:      MOV    AH,2           ;显示1个字符
         INT    21H
         DEC    BX                 ;处理下一个字符
         CMP    BX,0               ;是否为0?
         JNZ    CHANGE10           ;不为0转CHANGE10
           RET
DISPLAY16  ENDP
CODE  ENDS
END  START

本题如果采用堆栈传递参数的程序如下所示,请注意堆栈的变化。
DATA  SEGMENT
XBUF  DW  81
YBUF  DW  100
FBUF  DW  ?
DATA  ENDS
STACK  SEGMENT
TOP  DW  20 DUP(?)
STACK  ENDS
CODE  SEGMENT
ASSUME  CS:CODE,DS:DATA,SS:STACK
START:MOV  AX,DATA        ;给DS赋值
        MOV  DS,AX
        MOV  AX,STACK       ;给SS赋值
        MOV  SS,AX
        MOV  SP,SIZE  TOP     ;确定SP的指向位置
        MOV  AX,XBUF         ;取被开方数X
        PUSH  AX                ;压入堆栈
        CALL  SQROOT
        POP  AX                  ;取X平反根暂存AX中
        MOV  DX,YBUF          ;取被开方数Y
        PUSH  DX                 ;压入堆栈
        CALL  SQROOT
        POP  DX                  ;取Y平反根存入DX中
        ADD  AX ,DX            ; +
        MOV  FBUF,AX           ;送入FBUF单元
        MOV  SI,FBUF
        CALL DISPLAY16
        MOV  AH,4CH
        INT  21H
;*  *  *  *  *  *  *
;子程序名:SQROOT
;功能:求平方根运算
;输入参数:压入堆栈区
;输出参数:位于堆栈区
;*  *  *  *  *  *  *
SQROOT  PROC  NEAR
        PUSH  BP
        MOV  BP,SP    ;定位
        PUSH  AX
        PUSH  BX
        PUSH  CX
        MOV  AX,[BP+4]    ;取被开方数
        SUB  CX,CX        ;CX置0
AGAIN:MOV  BX,CX       ;下面三条指令使BX=2*CX+1
        ADD  BX,BX
        INC  BX
        SUB  AX,BX
        JC  OVER            ;不够减转OVER
        INC  CX
        JMP  AGAIN
OVER:MOV  [BP+4],CX    ;平方根放回原堆栈区
        POP  CX
        POP  BX
        POP  AX
        POP  BP
        RET
SQROOT  ENDP

 

;子程序名:DISPLAY16
;功能:以移位方式显示16进制数
;占用寄存器:BX,CL,AX,DX
;输入参数:要显示数据在SI中
;输出参数:无

DISPLAY16   PROC
         MOV    BX,4         ;每个字显示4个16进制字符
CHANGE10:      MOV    CL,4         ;准备左移4位(除以16)
         ROL    SI,CL            ;SI循环移4位
         MOV    DX,SI            ;转存到DX
         AND    DX,0FH            ;清高12位
         ADD    DL,30H       ;一个16进制数变为ASCII码值
         CMP    DL,3AH       ;是否小于10?
         JB     CHANGE12       ;如果小于10转显示
         ADD    DL,7           ;否则为A到F之间数,加7
CHANGE12:      MOV    AH,2           ;显示1个字符
         INT    21H
         DEC    BX                 ;处理下一个字符
         CMP    BX,0               ;是否为0?
         JNZ    CHANGE10           ;不为0转CHANGE10
         RET
DISPLAY16  ENDP
CODE  ENDS
END  START

思考:请编写求解一元二次方程AX2+BX+C=0的程序。




https://m.sciencenet.cn/blog-2551-215319.html

上一篇:汇编语言实验手册详细目录
下一篇:文理分科随感

0

发表评论 评论 (3 个评论)

数据加载中...
扫一扫,分享此博文

Archiver|手机版|科学网 ( 京ICP备07017567号-12 )

GMT+8, 2024-5-4 04:06

Powered by ScienceNet.cn

Copyright © 2007- 中国科学报社

返回顶部