DJ13-2 汇编语言程序设计

目录

一、顺序程序设计

二、分支程序设计

1. 用比较/测试命令+条件转移指令实现分支

2. 采用跳转表实现多路分支

三、循环程序设计

1. 计数循环程序设计

2. 条件判断循环程序设计

四、子程序设计

1. 子程序设计举例

2. 主程序和子程序设计举例


一、顺序程序设计

举例:利用学号查询学生数学成绩表。

程序流程:

源程序:

DSEG SEGMENT
    TABLE DB 81, 78, 90, 64, 85, 76, 93, 82, 57, 80
          DB 73, 62, 87, 77, 74, 86, 95, 91, 82, 71
    NUM DB 8   ; 存放学号
    MATH DB ?  ; 存放成绩
DSEG ENDS
SSEG SEGMENT STACK
    DW 20H DUP(0)
SSEG ENDS
CSEG SEGMENT
    ASSUME CS:CSEG, DS:DSEG, SS:SSEG
START:
    MOV AX, DSEG
    MOV DS, AX

    MOV BX, OFFSET TABLE
    MOV AH, 0        ; 否则BX+AX时AH内容是随机的
    MOV AL, NUM      ; 将学号送入AL
    DEC AL           ; 偏移量=学号-1
    ADD BX, AX       ; 不能BX+AL
    MOV AL, [BX]     ; 查到成绩送入AL
    MOV MATH, AL     ; 存储器之间不能直接传送

    MOV AH, 4CH      ; 返回DOS
    INT 21H
CSEG ENDS
    END START

二、分支程序设计

1. 用比较/测试命令+条件转移指令实现分支

(1)单分支结构

举例计算字单元 DMem 中带符号数的绝对值,并将结果存储于数据段 RESULT 中。

程序流程:

源程序:

DSEG SEGMENT
    DMem DW -5
    RESULT DW 0
DSEG ENDS
SSEG SEGMENT STACK
    DW 20H DUP(0)
SSEG ENDS
CSEG SEGMENT
    ASSUME CS:CSEG, DS:DSEG, SS:SSEG
START:
    MOV AX, DSEG
    MOV DS, AX

    MOV AX, DMem
    CMP AX, 0       ; 比较/测试
    JGE NOTNEG
    NEG AX          ; 特殊处理:负数需要求补
NOTNEG:
    MOV RESULT, AX  ; 共同事务:将数的绝对值存储到数据段

    MOV AH, 4CH     ; 返回DOS
    INT 21H    
CSEG ENDS
    END START

 需要注意的是,条件满足时转移,否则执行下一条语句。

; 另一种写法
    CMP AX, 0       ; 比较/测试
    JL ISNEG
    JMP NOTNEG
ISNEG:              ; 为负
    NEG AX
NOTNEG:             ; 为正
    MOV RESULT, AX

 因此,需要合理选择分支条件,同时理解与高级语言的差别。

(2)双分支结构

举例:编写一个能够显示 BX 二进制最高位的程序段。

程序流程:

 源程序:

DSEG SEGMENT

DSEG ENDS
SSEG SEGMENT STACK
    DW 20H DUP(0)
SSEG ENDS
CSEG SEGMENT
    ASSUME CS:CSEG, DS:DSEG, SS:SSEG
START:
    MOV AX, DSEG
    MOV DS, AX

    SHL BX, 1       ; 左移得到最高位
    JC ONE          ; 比较/测试
    MOV DL, '0'     ; 程序段1
    JMP DISPLAY
ONE:
    MOV DL, '1'     ; 程序段2
DISPLAY:
    MOV AH, 2       ; 共同事务
    INT 21H

    MOV AH, 4CH     ; 返回DOS
    INT 21H    
CSEG ENDS
    END START

另一种写法:

    AND BX, 8000H
    JNZ ONE         ; 比较/测试
    MOV DL, '0'     ; 程序段1
    JMP DISPLAY
ONE:
    MOV DL, '1'     ; 程序段2
DISPLAY:
    MOV AH, 2       ; 共同事务
    INT 21H

2. 采用跳转表实现多路分支

举例:设某程序有 10 路分支,分别为:BRAND1、BRAND2、...、BRAND10 。试根据变量 N 的值(1~10),将程序转移到其中的一路分支去。

根据 N 的值形成查表地址:(N−1) * 2 + 表首址

程序流程:

 源程序:

DSEG SEGMENT
    ATABLE DW BRAND1, BRAND2, BRAND3, BRAND4, BRAND5
           DW BRAND6, BRAND7, BRAND8, BRAND9, BRAND10
    N DB 3
DSEG ENDS
SSEG SEGMENT STACK
    DW 20H DUP(0)
SSEG ENDS
CSEG SEGMENT
    ASSUME CS:CSEG, DS:DSEG, SS:SSEG
START:
    MOV AX, DSEG
    MOV DS, AX

    MOV AH, 0       ; 否则BX+AX时AH内容是随机的
    MOV AL, N       ; 送入变量N
    DEC AL          ; N-1
    SHL AL, 1       ; 2*(N-1),SAL也可
    MOV BX, OFFSET ATABLE
    ADD BX, AX
    MOV DX, [BX]
    JMP DX          ; 转移到N对应的分支入口地址

BRAND1: ...
    JMP FINAL
BRAND2: ...
    JMP FINAL
    ...
BRAND10: ...
    JMP FINAL

FINAL: ...

    MOV AH, 4CH     ; 返回DOS
    INT 21H    
CSEG ENDS
    END START

三、循环程序设计

1. 计数循环程序设计

举例:计算 1~100 数字之和,并将结果存入字变量 SUM 的程序段。

LOOP:① CX - 1 ② 判断 CX 是否为 0

    MOV AX, 0      ; 初始化
    MOV CX, 100    ; 初始化
AGAIN:             ; 循环体
    ADD AX, CX
    LOOP AGAIN     ; 控制条件
    MOV SUM, AX    ; 处理结果

2. 条件判断循环程序设计

举例:数据段的 ARY 字节数组中存放有 10 个无符号数,试找出其中最大者送入 MAX 字节单元。

程序流程:

源程序:

DSEG SEGMENT
    ARY DB 17, 5, 40, 0, 67
        DB 12, 34, 78, 32, 10
    MAX DB ?
DSEG ENDS
SSEG SEGMENT STACK
    DW 20H DUP(0)
SSEG ENDS
CSEG SEGMENT
    ASSUME CS:CSEG, DS:DSEG, SS:SSEG
START:
    MOV AX, DSEG
    MOV DS, AX

    MOV SI, OFFSET ARY  ; 初始化
    MOV CX, 9           ; 初始化
    MOV AL, [SI]        ; 初始化
LOP:
    INC SI
    CMP AL, [SI]
    JAE BIGGER
    MOV AL, [SI]
BIGGER:
    DEC CX
    JNZ LOP             ; 控制条件
    MOV MAX, AL         ; 处理结果

    MOV AH, 4CH
    INT 21H    
CSEG ENDS
    END START

四、子程序设计

  • 子程序是程序的一部分,是完成特定功能的程序段,它能够在程序中的任何地方被调用。

  • 子程序的调用与返回是由指令 CALL 和 RET 来完成的。

  • 子程序中一般都要使用寄存器,除了要返回参数的寄存器外,在子程序设计的开始部分,要将用到的寄存器进行压栈保存,在子程序结束返回调用程序之前要进行出栈恢复。

  • 子程序和调用程序直接的信息传送称为参数传递。

 

1. 子程序设计举例

举例:实现一个显示回车和换行功能的子程序。

先完成主要程序,再看需要用到哪些寄存器。 

DISPLAY PROC
    ; 压栈保存
    PUSH AX
    PUSH DX

    MOV DL, 0DH
    MOV AH, 2
    INT 21H

    MOV DL, 0AH
    MOV AH, 2
    INT 21H
    
    ; 出栈恢复
    POP DX
    POP AX
    
    RET
DISPLAY ENDP

2. 主程序和子程序设计举例

举例:将两个给定的二进制数 BIN1 和 BIN2(8 位和 16 位)逐位转换为 ASCII 码字符串,并存储于 ASCBUF 中。

程序流程:

源程序:

DSEG SEGMENT
    BIN1 DB 35H
    BIN2 DW 0AB48H
    ASCBUF DB 20H DUP(?)
DSEG ENDS
SSEG SEGMENT STACK
    DW 20H DUP(0)
SSEG ENDS
CSEG SEGMENT
    ASSUME CS:CSEG, DS:DSEG, SS:SSEG
START:
    MOV AX, DSEG
    MOV DS, AX

    XOR DX, DX      ; DX清零

    LEA DI, ASCBUF  ; 给出存放结果的首址
    MOV DH, BIN1    ; 给出待转换的数据
    MOV CX, 8       ; 给出转换的位数
    CALL BINASC     ; 调用转换子程序

    LEA DI, ASCBUF+8
    MOV DX, BIN2
    MOV CX, 16
    CALL BINASC

BINASC PROC
    PUSH AX

LOP:
    ROL DX, 1
    MOV AL, DL
    AND AL, 1       ; 保留最低位,屏蔽其它位
    ADD AL, 30H     ; 获取ASCII码
    MOV [DI], AL    ; 存放结果
    INC DI          ; 修改指针
    LOOP LOP        ; 修改计数,控制循环

    POP AX
    RET
BINASC ENDP

    MOV AH, 4CH
    INT 21H    
CSEG ENDS
    END START

子程序流程:

原理说明:为了适配 8 位和 16 位,统一使用 DX 寄存器进行循环移位。

子程序部分:

BINASC PROC
    PUSH AX

LOP:
    ROL DX, 1
    MOV AL, DL
    AND AL, 1       ; 保留最低位,屏蔽其它位
    ADD AL, 30H     ; 获取ASCII码
    MOV [DI], AL    ; 存放结果
    INC DI          ; 修改指针
    LOOP LOP        ; 修改计数,控制循环

    POP AX
    RET
BINASC ENDP

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值