《汇编语言》王爽(第四版) 第十章 实验10

这篇具有很好参考价值的文章主要介绍了《汇编语言》王爽(第四版) 第十章 实验10。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

文章目录

前言

一、子程序1 显示字符串

1.实验任务

2.分析

(1)如何在指定位置显示

(2)如何显示指定颜色

(3)保存子程序中用到的寄存器

3.代码

二、子程序2 解决除法溢出的问题

1.实验任务

2.代码

三、子程序3 数值显示

1.实验任务

2.显示一个word型数据的代码

总结


前言

本文是王爽老师《汇编语言》(第四版) 第十章 实验10 的分析及代码。

本实验的内容是:编写三个子程序(显示字符串、解决除法溢出的问题、数值显示)。

一、子程序1 显示字符串

1.实验任务

编写一个子程序,向外提供可以调用的接口,能够在指定的行号、列号,用指定的颜色,显示一个用0结束的字符串。

assume cs:code
data segment
  db 'Welcome to masm!',0
data ends

code segment
start:
    mov dh,8    ;指定行号
    mov dl,3    ;指定列号
    mov cl,2    ;指定颜色

    mov ax,data    ;设置ds
    mov ds,ax
    mov si,0    ;设置ds:[si]指向当前要显示的字符

    call show_str    ;调用子程序,显示字符串

    mov ax,4c00H    ;程序返回
    int 21H
 
show_str:        
    

code ends
end start

2.分析

(1)如何在指定位置显示

第一屏的内容所对应的内存地址空间为B8000H~B8F9FH,因而可以令这一段的段地址为B800H。

显示器一屏可以显示25行,每行80个字符(每个字符占2个字节)。因此第一个字符应该在的偏移地址应该是 ( dh*80*2 + dl*2 )。注意,任务中给出的列号是指显示屏上的第几个字符,而不是指该行的第几个字节,显示区每个字符占两个字节!

(2)如何显示指定颜色

属性字节中,最低三位可以用来设置颜色。这个属性字节的内容应当是寄存器cl的值。

(3)保存子程序中用到的寄存器

子程序中会使用到dh  dl  si  等寄存器,因而在子程序的一开始要把这些寄存器的值压入栈,在子程序返回前再pop出来。由此可知需要一段栈空间。

3.代码

assume cs:code,ds:data,ss:stack
data segment
    db 'Welcome to masm!',0     ;要显示的字符串
data ends

stack segment
    dw 8 dup(0)        ;用于在调用子程序时存放寄存器值
stack ends

code segment
start:
    mov dh,8    ;指定行号
    mov dl,3    ;指定列号
    mov cl,2    ;指定颜色

    mov ax,data    ;设置ds
    mov ds,ax
    mov si,0    ;设置ds:[si]指向data段中当前要显示的字符
    mov ax,stack    ;设置栈顶
    mov ss,ax   
    mov sp,10H 

    call show_str    ;调用子程序,显示字符串

    mov ax,4c00H    ;程序返回
    int 21H
 
show_str:      
                ;功能:将data段中首地址为ds:si的字符,以指定颜色显示在屏幕指定位置
                ;参数:dh 行号, dl 列号 ,cl 颜色
                ;返回:无
               
    push dx        ;将子程序用到的寄存器压入栈
    push si
    push ax
    push bx
    
    mov ax,0B800H    ;设置es为显示区段地址
    mov es,ax
    
    mov ax,00A0H    ;设置首字符显示的地址
    mul dh
    mov dh,0
    add ax,dx 
    add ax,dx
    mov bx,ax    ;bx是显示区的偏移地址
        
    mov al,cl    ;用al存储属性字节
    mov ch,0
    mov si,0
    
    s:                ;循环读取字符并显示
    mov cl,ds:[si]
    jcxz ok            ;若读到0,就退出循环
    mov es:[bx],cl
    inc bx
    mov es:[bx],al
    inc bx
    inc si
    jmp short s

    ok:        ;将寄存器的值pop出来
    pop bx
    pop ax
    pop si
    pop dx
    
    ret    ;返回

code ends
end start

二、子程序2 解决除法溢出的问题

1.实验任务

(1)写一个子程序,功能是进行不会产生溢出的除法运算。被除数为dword型,除数为word型,结果为dword型。

参数:ax = dword型数据的低16位 ;dx = dword型数据的高16位 ;cx = 余数

返回: dx = 结果的高16位 ;ax = 结果的低16位 ; cx = 余数

(2)可以参考的公式如下。

X 为被除数,H 为X的高16位,L 为X的低16位 , N 除数。

int()表示取商,rem()表示取余数。

则  X/N = int( H/N ) * 65536 + [rem( H/N) * 65536 + L]/N   。

(通过实际写代码会对这个公式的巧妙性有更为深入的理解。)

2.代码

assume cs:code,ss:stack
stack segment
    dw 0
stack ends

code segment
start:

    mov ax,stack    ;设置栈顶
    mov ss,ax
    mov sp,10H

    mov ax,4240H    ;被除数的低16位
    mov dx,000FH    ;被除数的高16位
    mov cx,0AH    ;除数
    call divdw    ;调用子程序

divdw:    ;功能:计算word型被除数与byte型除数的除法
            ;参数:  ax=被除数低16位,dx=被除数高16位,cx = 除数
            ;返回:  ax=商的低16位,dx=商的高16位,cx = 余数

    ;计算公式: X/N = int( H/N ) * 65536 + [rem( H/N) * 65536 + L]/N  
    ;其中X为被除数,N为除数,H为被除数的高16位,L为被除数的低16位,
    ;int()表示结果的商,rem()表示结果的余数。
    
    push bx    ;bx是额外用到的寄存器,要压入栈

    mov bx,ax    ;bx=L
    mov ax,dx    ;ax=H
    mov dx,0    ;dx=0
    div cx        ;计算H/N,结果的商即int(H/N)保存在ax,余数即rem(H/N)保存在dx

                    ;接下来要计算int(H/N)*65536,思考一下,65536就是0001 0000 H,
                    ;因此计算结果就是,高16位=int(H/N),低16位为0000H。

    push ax        ;将int(H/N)*65536结果的高16位,即int(H/N),压入栈
    mov ax,0
    push ax        ;将int(H/N)*65536结果的低16位,即0000H,压入栈

                    ;接下来要计算 rem(H/N)*65536 ,同理可得,
                    ;计算结果为 高16位=  rem(H/N)*65536 ,即此时dx的值,
                    ;低16位为 0000H。

    mov ax,bx    ;ax = bx = L ,即 [rem(H/N)*65536 + L]的低16位
    div cx        ;计算 [rem( H/N) * 65536 + L]/N ,结果的商保存在ax,余数保存在dx

                    ;接下来要将两项求和。  左边项的高、低16位都在栈中,
                    ;其中高16位就是最终结果的高16位,低16位是0000H。
                    ;右边项的商为16位,在ax中,也就是最终结果的低16位,
                    ;余数在dx中,也就是最终结果的余数。

    mov cx,dx    ;cx = 最终结果的余数
    pop bx        ;cx = int(H/N)*65536结果的低16位,即0000H。
    pop dx        ;bx = int(H/N)*65536结果的高16位,即最终结果的高16位

    pop bx    ;还原bx的值

    mov ax,4c00H
    int 21H
code ends
end start

三、子程序3 数值显示

1.实验任务

(1)将data段中的数据以十进制的形式显示出来。应该编写一个通用的子程序,将一个给定的word型数据转为以十进制显示的字符串。而字符的显示功能,可以调用上边写的子程序1来完成。

子程序描述:

名称:dtoc

功能:将word型数据转变为表示十进制数的字符串,字符串以0为结尾符。

参数:ax = word型数据 ; ds:si 指向字符串的首地址

返回:无

(2)代码

assume cs:code,ds:data
data segment
    db 10 dup(0)
data ends

code segment
start:
    mov bx,data    ;设置ds段地址
    mov ds,bx

    mov ax,12666    ;要显示的数据
    mov si,0    ;ds:si指向字符串首地址
    call dtoc    ;将数据转为十进制字符

    mov dh,8    ;在屏幕第几行开始显示
    mov dl,3    ;在屏幕第几列开始显示
    mov cl,2    ;显示的字符的颜色
    call show_str

    mov ax,4c00H    ;程序返回
    int 21H

dtoc:


show_str:        


code ends
end start

2.显示一个word型数据的代码

这里要把十六进制(或者说二进制)的数据转换为十进制,就要用到除法,也就是div指令,有可能出现除法溢出的问题,可以调用子程序2(解决除法溢出问题)来解决!而转换成十进制的字符数字之后,可以调用子程序1(显示字符串)来显示。

assume cs:code,ds:data,ss:stack
data segment
    db 10 dup(0)
data ends

stack segment
    dw 16 dup(0)    ;32字节
stack ends

code segment
start:
    mov bx,data    ;设置ds段地址
    mov ds,bx
    mov bx,stack    ;设置栈顶
    mov ss,bx
    mov sp,20H

    mov ax,12666    ;要显示的数据
    mov si,0    ;ds:si指向字符串首地址
    call dtoc    ;将数据转为十进制字符
    
    mov dh,8    ;在屏幕第几行开始显示
    mov dl,3    ;在屏幕第几列开始显示
    mov cl,2    ;显示的字符的颜色
    call show_str

    mov ax,4c00H    ;程序返回
    int 21H


dtoc:    ;功能:将给定的word型数据转为十进制字符形式,存入data段,首地址ds:si
            ;参数:ax 指定的word数据 
            ;返回:ds:si指向data段字符串首地址
    
    push bx;    ;将子程序用到的寄存器压入栈
    push cx;    
    push dx;
    push si;

    mov bx,000aH    ;bl = 除数,bh = 一共除了几次
    mov dx,0    ;即将进行除法,dx是高16位,低16位在ax中
    pushyushu:
    mov cx,0
    mov cl,bl    ;cx = 除数
    call divdw    ;调用不会溢出的除法函数,结果的商的高16位,在dx中,
                    ;低16位在ax中,余数在cx中,余数一定<10

    push cx        ;cx=余数,这个余数在显示的时候要倒序显示,因此先压入栈
    inc bh        ;记录将余数压入栈的次数
    mov cx,ax    ;cx = ax = 结果的商的低16位
    add cx,dx    ;dx是结果的商的高16位,ax和dx一定都是非负数
    jcxz popyushu        ;若cx=0,则说明除法计算已经完毕,跳转下一步执行
    jmp short pushyushu

    popyushu:
    mov ch,0
    mov cl,bh    ;ch=0,所以cx = 将余数压入栈的次数,也就是接下来的循环次数
    s1:
    pop ax;        ;从栈中pop出一个余数
    add ax,30H    ;从数字转为对应的数字字符
    mov ds:[si],al    ;用al就够了
    inc si
    loop s1
    
    pop si    ;子程序结束,将寄存器的值pop出来
    pop dx;    
    pop cx;
    pop bx;
    
    ret

divdw:    ;功能:计算word型被除数与byte型除数的除法
            ;参数:  ax=被除数低16位,dx=被除数高16位,cx = 除数
            ;返回:  ax=商的低16位,dx=商的高16位,cx = 余数

    ;计算公式: X/N = int( H/N ) * 65536 + [rem( H/N) * 65536 + L]/N  
    ;其中X为被除数,N为除数,H为被除数的高16位,L为被除数的低16位,
    ;int()表示结果的商,rem()表示结果的余数。

    push bx    ;bx是额外用到的寄存器,要压入栈

    mov bx,ax    ;bx=L
    mov ax,dx    ;ax=H
    mov dx,0    ;dx=0
    div cx        ;计算H/N,结果的商即int(H/N)保存在ax,余数即rem(H/N)保存在dx

                    ;接下来要计算int(H/N)*65536,思考一下,65536就是0001 0000 H,
                    ;因此计算结果就是,高16位=int(H/N),低16位为0000H。

    push ax        ;将int(H/N)*65536结果的高16位,即int(H/N),压入栈
    mov ax,0
    push ax        ;将int(H/N)*65536结果的低16位,即0000H,压入栈

                    ;接下来要计算 rem(H/N)*65536 ,同理可得,
                    ;计算结果为 高16位=  rem(H/N)*65536 ,即此时dx的值,
                    ;低16位为 0000H。

    mov ax,bx    ;ax = bx = L ,即 [rem(H/N)*65536 + L]的低16位
    div cx        ;计算 [rem( H/N) * 65536 + L]/N ,结果的商保存在ax,余数保存在dx

                    ;接下来要将两项求和。  左边项的高、低16位都在栈中,
                    ;其中高16位就是最终结果的高16位,低16位是0000H。
                    ;右边项的商为16位,在ax中,也就是最终结果的低16位,
                    ;余数在dx中,也就是最终结果的余数。

    mov cx,dx    ;cx = 最终结果的余数
    pop bx        ;cx = int(H/N)*65536结果的低16位,即0000H。
    pop dx        ;bx = int(H/N)*65536结果的高16位,即最终结果的高16位

    pop bx    ;还原bx的值

    ret

    
show_str:
                ;功能:将data段中首地址为ds:si的字符,以指定颜色显示在屏幕指定位置
                ;参数:dh 行号, dl 列号 ,cl 颜色
                ;返回:无

    push dx        ;将子程序用到的寄存器压入栈
    push si
    push ax
    push bx
    
    mov ax,0B800H    ;设置es为显示区段地址
    mov es,ax
    
    mov ax,00A0H    ;设置首字符显示的地址
    mul dh
    mov dh,0
    add ax,dx 
    add ax,dx
    mov bx,ax    ;bx是显示区的偏移地址
        
    mov al,cl    ;用al存储属性字节
    mov ch,0
    mov si,0
    
    s:                ;循环读取字符并显示
    mov cl,ds:[si]
    jcxz ok            ;若读到0,就退出循环
    mov es:[bx],cl
    inc bx
    mov es:[bx],al
    inc bx
    inc si
    jmp short s

    ok:        ;将寄存器的值pop出来
    pop bx
    pop ax
    pop si
    pop dx
    
    ret    ;返回


code ends
end start


总结

本文是王爽老师《汇编语言》(第四版) 第十章 实验10 编写3个子程序 的分析及代码。这个实验任务要按顺序完成,因为后边的任务会用到前边写的子程序。文章来源地址https://www.toymoban.com/news/detail-477218.html

到了这里,关于《汇编语言》王爽(第四版) 第十章 实验10的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • <微机原理>[汇编语言]-[实验八]矩阵键盘应用实验

    实验八 矩阵键盘应用实验.doc 掌握矩阵式键盘识别技术 进一步掌握数码管显示原理 Keil5 普中A2开发板 stc-isp 用单片机的并行口P1接矩阵键盘,在数码管上显示每个按键的“0—F”序号。对应的按键的序号排列如图所示: 使用EQU伪指令重新命名R0为KEY_VALUE方便代码后续的理解。

    2024年02月10日
    浏览(32)
  • 汇编语言:矩阵式键盘扫描实验

    利用4x4矩阵键盘和一个LED数码管构成简单的输入显示系统,实现对键盘的扫描和LED数码管的显示键盘按下键的键号。共有4x4个按键和一个数码管,16个按键的键号分别对应十六进制数字:0~F。单机相应按键,数码管就会显示相应的数字。 数码管:这里采用共阳极数码管 CA为共

    2024年02月11日
    浏览(68)
  • <微机原理>[汇编语言]-[实验七]数码管动态显示实验

    实验一 软件开发环境和简单程序设计 实验二 I_O输入输出实验 实验三 键盘扫描显示实验 实验四 中断实验 实验五 定时器实验 实验六 串行口实验 实验七 数码管动态显示实验 实验八 矩阵键盘应用实验 实验九 电子时钟 微机原理实验课程,会陆续根据目录更新文章 掌握LED八段

    2024年02月07日
    浏览(33)
  • 【汇编语言与微机原理】实验五:键盘按键与数码管显示

    熟悉星研集成开发环境,掌握微机接口程序编写调试的基本方法。 掌握矩阵式键盘工作原理及识别按键的方法。 掌握8段数码管显示数字或字符的工作原理和它的使用方法。 掌握用8255扫描键盘及用8255刷新数码管的显示方法。 在2*8(看 着像4*4,实际上是2*8 )的小键盘上按下

    2024年02月16日
    浏览(32)
  • 实验一8086计CPU系统寻址方式和汇编语言程序设计

    实验一8086计CPU系统寻址方式和汇编语言程序设 一、实验目的 (1)掌握8086CPU系统的逻辑地址和寻址方式。 (2)掌握8086CPU系统中机器数的表示方式。 (3)掌握指令的机器码表示方法。 (4)掌握堆栈的概念和操作过程。 (5)掌握集成开发环境下的程序设计和调试方法。 (6)掌握汇编语言实

    2023年04月22日
    浏览(39)
  • 南京邮电大学汇编语言程序设计实验二(用户登录验证程序的设计)

    1.掌握循环程序的编写以及结束循环的方法。 2.掌握DOS、BIOS功能调用的使用方法。 用户登录验证程序的实现 程序执行后,给出提示操作,请用户键入用户名和密码;用户在键入密码时,程序不回显键入字符;只有当用户键入的用户名,密码字符串和程序内定的字符串相同时

    2023年04月18日
    浏览(43)
  • 汇编语言实验8:BIOS/DOS功能调用与宏指令程序设计

    掌握汇编语言程序设计的基本方法和技能 掌握汇编语言源程序的编辑汇编连接和执行的完整过程 通过上机操作理解宏定义、宏调用、宏展开的概念,熟练运用宏功能编写程序 掌握BIOS/DOS基础功能的实现调用方法 理解常用的DOS功能调用的基本使用,能熟练运用1号,2号,9号,

    2024年02月03日
    浏览(57)
  • 汇编语言笔记(一)——汇编语言基础

    一、开发环境 我使用visual studio 2022 preview,其他版本的设置大同小异。 第一步: 打开visual studio,点击“创建新项目”: 第二步: visual studio并没有专门的汇编项目,所以需要挂羊头卖狗肉,选择C++空项目 第三步: 输入项目名称,点击创建 第四步: 鼠标右键单击项目名称—

    2024年02月05日
    浏览(31)
  • 汇编语言—常见汇编指令汇总

    mov    寄存器 ,数据                如:mov ax ,8 mov   寄存器,寄存器              如:mov ax,bx mov   寄存器,内存单元          如:mov ax,[0] mov   内存单元,寄存器          如:mov [0],ax mov   段寄存器,寄存器          如:mov ds,ax add   寄存器,数据

    2024年02月10日
    浏览(32)
  • 5.7 汇编语言:汇编高效乘法运算

    乘法指令是一种在CPU中实现的基本算术操作,用于计算两个数的乘积。在汇编语言中,乘法指令通常是通过 mul(无符号乘法) 和 imul(有符号乘法) 这两个指令实现的。由于乘法指令在执行时所消耗的时钟周期较多,所以编译器在优化代码时通常会尝试将乘法操作转换为更

    2024年02月11日
    浏览(27)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包