微机原理 实验08:子程序设计—求最大最小值的平均值(汇编语言)(理解段内和段外过程)

目录

一、实验目的

二、实验内容

流程图

代码

理解:

使用段内过程:

使用段外过程:

对于进位和溢出的优化问题:

对无符号数进位进行处理:

程序编译信息截图

程序运行结果截图

三、实验调试过程记录、结果分析及评价


作者:李宗霖        日期:2023/5/22

一、实验目的

1、学习子程序(过程)的定义和调用方法。

2、学习$、OFFSET等伪指令。

3、进一步学习程序执行的流程。

二、实验内容

设有一数据区有10个有符号数的字节数据(如55,78H,43,-19,0,1,10,80H,0FFH,100),位于数据段偏移地址为1000H开始的10个内存单元中。编写程序找出其中的最大数和最小数,分别存入BH和BL;然后求其中最大值和最小值的平均值,存入AL。

要求:将求最大最小值设计为子程序,并画出子程序流程图;在主程序里调用该子程序、求平均值,并绘制主程序流程图。

流程图

代码

理解:

方便大家理解这里用面对对象的类来进行类比,只是类比,汇编语言没有类的概念!

        段内过程就像在一个类里面,只用改变偏移地址即可调用。段外过程就像不在一个类中的函数,要调用就得申明,也就是这里存储要调用代码段的段地址和偏移地址。

使用段内过程:

DATA            SEGMENT                 ; 定义数据段
ARRAY           DB 55, 78H, 43, -19, 0, 1, 10, 80H, 0FFH, 100
                                        ; MAX: 78H = 120D, MIN: 80H = -128D
NUM             DW 10D                  ; 数据的数量   
OFFS            DW 1000H                ; 存放数据的偏移地址
DATA            ENDS

CODE            SEGMENT                 ; 定义代码段
ASSUME          CS: CODE, DS: DATA      ; 将各段内容指定寄存器
START:          MOV AX, DATA
                MOV DS, AX
                MOV ES, AX              ; 将数据段DATA的首地址放入DS, ES
                MOV AX, 0H
         
                MOV CX, NUM             ; 传数据数量
                MOV SI, OFFSET ARRAY    ; 传数据地址给SI
                MOV DI, OFFS            ; 目标偏移地址传给DI
                REP MOVSB               ; 将数据段的10条字节数据存入指定偏移地址
                                
                CALL FIND_MAX_MIN       ; 调用子程序,寻找最大值和最小值 
                
                MOV AL, BH              ; 将最大值放入AL
                ADD AL, BL              ; 将最小值加到AL
                SAR AL, 1               ; 将AL右移一位,相当于除以2,得到平均值

                MOV AH, 4CH             ; 结束主程序运行
                INT 21H                 
         
FIND_MAX_MIN    PROC NEAR               ; 定义段内子程序,寻找最大值和最小值                             
                PUSH AX                 ; 保护寄存器AX
                PUSH CX                 ; 保护寄存器CX
                PUSH SI                 ; 保护寄存器SI       
                
                MOV CX, NUM             ; CX传入数据数量
                MOV SI, OFFS            ; 用SI指向数据存放地址
                MOV BH, -128            ; 初始化最大值为-128(有符号数的最小值)
                MOV BL, 127             ; 初始化最小值为127(有符号数的最大值)

FIND_LOOP:      MOV AL, [SI]            ; 取出当前元素放入AL 
                CMP AL, BH              ; 比较当前元素和最大值 
                JLE CMP_MIN             ; 如果当前元素小于等于最大值,与最小值比较
                MOV BH, AL              ; 如果当前元素大于最大值,更新最大值
                 
CMP_MIN:        CMP AL, BL              ; 比较当前元素和最小值 
                JGE NEXT_ELEMENT        ; 如果当前元素大于等于最小值,下一个数
                MOV BL, AL              ; 如果当前元素小于最小值,更新最小值
                
NEXT_ELEMENT:   INC SI                  ; 增加数组地址指针 
                LOOP FIND_LOOP          ; 循环计数器减一,如果CX不为零,继续循环                
                
                POP SI                  ; 恢复寄存器SI 
                POP CX                  ; 恢复寄存器CX 
                POP AX                  ; 恢复寄存器AX 
                RET                     ; 返回主程序
FIND_MAX_MIN    ENDP                    ; 结束子程序定义                
                
         
CODE            ENDS                    ; 代码段结束
                END START

使用段外过程:

DATA            SEGMENT                 ; 定义数据段
ARRAY           DB 55, 78H, 43, -19, 0, 1, 10, 80H, 0FFH, 100
                                        ; MAX: 78H = 120D, MIN: 80H = -128D
NUM             DW 10D                  ; 数据的数量   
OFFS            DW 1000H                ; 存放数据的偏移地址
DATA            ENDS

CODE            SEGMENT                 ; 定义代码段
ASSUME          CS: CODE, DS: DATA      ; 将各段内容指定寄存器
START:          MOV AX, DATA
                MOV DS, AX
                MOV ES, AX              ; 将数据段DATA的首地址放入DS, ES
                MOV AX, 0H
         
                MOV CX, NUM             ; 传数据数量
                MOV SI, OFFSET ARRAY    ; 传数据地址给SI
                MOV DI, OFFS            ; 目标偏移地址传给DI
                REP MOVSB               ; 将数据段的10条字节数据存入指定偏移地址
                                
                MOV WORD PTR [DI+2], OFFSET FIND_MAX_MIN 
                                        ; 将子程序的偏移地址存入DI+2处
                MOV WORD PTR [DI+4], CODE_FIND          
                                        ; 将子程序的段地址存入DI+4处
                CALL FAR PTR [DI+2]     ; 调用子程序,寻找最大值和最小值
                MOV AL, BH              ; 将最大值放入AL
                ADD AL, BL              ; 将最小值加到AL
                SAR AL, 1               ; 将AL右移一位,相当于除以2,得到平均值

                MOV AH, 4CH             ; 结束主程序运行
                INT 21H                                   
CODE            ENDS
                
CODE_FIND       SEGMENT                 ; 定义子程序代码段
ASSUME          CS:CODE_FIND            ; 代码段指定寄存器 
FIND_MAX_MIN    PROC FAR                ; 定义段内子程序,寻找最大值和最小值                             
                PUSH AX                 ; 保护寄存器AX
                PUSH CX                 ; 保护寄存器CX
                PUSH SI                 ; 保护寄存器SI       
                
                MOV CX, NUM             ; CX传入数据数量
                MOV SI, OFFS            ; 用SI指向数据存放地址
                MOV BH, -128            ; 初始化最大值为-128(有符号数的最小值)
                MOV BL, 127             ; 初始化最小值为127(有符号数的最大值)

FIND_LOOP:      MOV AL, [SI]            ; 取出当前元素放入AL 
                CMP AL, BH              ; 比较当前元素和最大值 
                JLE CMP_MIN             ; 如果当前元素小于等于最大值,与最小值比较
                MOV BH, AL              ; 如果当前元素大于最大值,更新最大值
                 
CMP_MIN:        CMP AL, BL              ; 比较当前元素和最小值 
                JGE NEXT_ELEMENT        ; 如果当前元素大于等于最小值,下一个数
                MOV BL, AL              ; 如果当前元素小于最小值,更新最小值
                
NEXT_ELEMENT:   INC SI                  ; 增加数组地址指针 
                LOOP FIND_LOOP          ; 循环计数器减一,如果CX不为零,继续循环                
                
                POP SI                  ; 恢复寄存器SI 
                POP CX                  ; 恢复寄存器CX 
                POP AX                  ; 恢复寄存器AX 
                RETF                    ; 返回主程序
FIND_MAX_MIN    ENDP                    ; 结束子程序定义  
CODE_FIND       ENDS 
                END START

对于进位和溢出的优化问题:

               ;不考虑溢出进位求平均数
                MOV AL, BH              ; 将最大值放入AL
                ADD AL, BL
                SAR AL, 1               ; 将AL右移一位,相当于除以2,得到平均值

                MOV AH, 4CH             ; 结束主程序运行

               ;优化考虑进位、溢出改为如下:

                JNO NOT_OVERFLOW        ; 如果不溢出跳转NOT_OVERFLOW处理
                ADC AH, 0H              ; 当最大最小值都是80H进位
                SHR AX, 1               ; 溢出将AL逻辑右移一位,得到平均值
                JMP FINISH              ; 跳转结束
                
NOT_OVERFLOW:   SAR AL, 1               ; 在不溢出时,用算术右移一位

FINISH:         MOV AH, 4CH             ; 结束主程序运行
                

对无符号数进位进行处理:

               ;无符号数考虑进位求平均数
                MOV AL, BH              ; 将最大值放入AL
                ADD AL, BL
                ADC AH, 0H
                SHR AX, 1               ; 将AL右移一位,相当于除以2,得到平均值

                MOV AH, 4CH             ; 结束主程序运行
                

程序编译信息截图

程序运行结果截图

三、实验调试过程记录、结果分析及评价

  1. 特别注意有符号数字节取值范围:-128~127

  2. 注意段内过程还段外过程,缺省默认是段内NEAR,段外FAR

  3. 段外需要注意返回主程序是RETF,调用子程序是要先存储子程序偏移地址和段地址,不然访问不到:

  4. ​求平均数注意有符号运算用算数右移:SAR

  5. (2023/5/23优化) 如果上题是无符号数,只需将进位存入AH中,做除法时目标为AX即可。

  6. (2023/5/23优化)在求平均数的时候注意对溢出的处理:如果溢出采用逻辑右移,不溢出采用算数右移。最特殊 的情况是最大最小值都为80H,进位到AH,用逻辑右移处理。

  • 10
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Leisure_水中鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值