当前位置: 首页 > news >正文

实验十 编写子程序《汇编语言》- 王爽

一. 显示字符串

1. 需求

        显示字符串是现实工作中经常要用到的功能,应该编写一个通用的子程序来实现这个功能。我们应该提供灵活的调用接口,使用者可以决定显示的位置(行、列)、内容和颜色。

        子程序描述

        名称:show_str

        功能:在指定的位置,用指定的颜色,显示一个用0结尾的字符串

        参数:(dh) = 行号(取值范围在0 ~ 24),dl = 列号(取值范围在0 ~ 79),

                   (cl) = 颜色,ds:si指向字符串的首地址

        返回值:无

2. 分析

        在8086CPU中,B8000h ~ BFFFFh 这32kb空间,是80 x 25彩色字符模式的显示缓冲区,显示缓冲区分为8页,每页有4kb(约等于4000字节),显示器可以显示任意一页的内容,一般情况下,显示第0页的内容,也就是说,B8000h ~ B8F9F 这4000个字节的内容会显示在显示器上。所以,可以让es寄存器指向显示缓冲器的首地址,作为显示缓冲区的段地址:es = 0B800h

        在 B8000h ~ B8F9F 这4000个字节中,分为25行,每一行占160个字节,显示80个字符,每个字符占2字节,低字节存放字符的assii码,高字节存放字符的属性,关于字符属性(闪烁,背景(底色),高亮,前景(字符色))等介绍,可以浏览以下博文了解实验9 根据材料编程《汇编语言》- 王爽-CSDN博客

所以,绿色字的字符属性为:0000 0010b = 2

3. 代码

示例:在屏幕的 8 行 3 列,用绿色显示data段中的字符串

assume cs:code, ds:data
data segmentdb 'welcome to masm!',0
data ends
code segment
start:mov ax, datamov ds, axmov dh, 8mov dl, 3mov cl, 2   ;字属性字节mov si, 0call show_strmov ax, 4c00hint 21h;名称:show_str
;功能:在指定的位置,用指定的颜色,显示一个以0结尾的字符串
;参数:dh=行号(取值范围:0-24),dl=列号(取值范围:0-79)
;      cl=颜色,ds:si指向字符串的首地址
;返回值:无
show_str:;B8000h-BFFFFh共32kb,是80 * 25彩色字符模式的显示缓冲区,每页4kb(4000字节),显示器可以显示任意一页的内容。;一般情况下,显示第0页的内容, 也就是说,B8000h ~ B8F9Fh 这4000个字节的内容会显示在显示器上。每行80个字,;每个字占2个字节,低字节存放字符的assii码,高字节为属性字节。所以每行占160个字节mov ax, 0B800h  ;显示缓冲区段地址mov es, ax;行mov al, 160     ;每行160个字节mul dh          ;8位乘法,一个数默认在al中,另一个在dh中,结果放在ax中mov bx, ax      ;行偏移字节;列mov al, 2       ;一个字占2个字节,低字节存放字符的assii码,高字节为属性字节mul dl          ;8位,乘法,一个数默认在al中,另一个在dl中,结果放在ax中add bx, ax      ;行偏移字节 + 列偏移字节 = 相对于显示缓冲区段地址总的偏移地址mov ch, 0mov dl, cl      ;循环中需要用到cx寄存器,所以把存放字体属性的字节存放在dl中
s:mov cl, ds:[si]jcxz ok         ;cx = 0,跳转到标号处执行,否则,继续顺序往下执行mov es:[bx], clmov es:[bx+1], dlinc siadd bx, 2loop sok:    retcode ends
end start

二. 解决除法溢出问题

1. 需求

        div 指令做除法,当进行8位除法的时候,用al存储结果的商,ah存储结果的余数;当进行16位除法的时候,用ax存储结果的商,dx存储结果的余数。可是现在有一个问题,如果结果的商大于al或ax所能存储的最大值,那么将引发CPU的一个内部错误,这个错误被称为:除法溢出,我们可以用下面的子程序 divdw 解决

        子程序描述

        名称:divdw

        功能:进行不会产生溢出的除法运算,被除数为 dword 型,除数为 word 型,结果为 dword 型

        参数:(ax) = dword 型数据的低16位

                   (dx) = dword 型数据的高16位

                   (cx) = 除数

        返回:(ax) = 结果的低16位,(dx) = 结果的高16位

                   (cx) = 结果的余数

2. 分析

数学公式:X/N = int(H/N)*65535 + [rem(H/N)*65535 + L]/N

X:被除数,范围:[0, FFFFFFFF]

N:除数,范围:[0, FFFF]

H:X的高16位,范围:[0, FFFF]

L:X的低16位,范围:[0, FFFF]

int():描述性运算符,取商,比如,int(38/10) = 3

rem():描述性运算符,取余,比如,int(38/10) = 8

所以,dword 型数据 X 除以 word 型数据 N,可以转换成等号右边的公式来表达,而等号右边的所有除法运算都可以用div指令来做,而且肯定不会导致溢出问题。

3. 代码

示例:计算1000000/10(F4240h/0Ah)

assume cs:code, ds:stack
stack segment   dw 16 dup (0)
stack ends
code segment
start:;初始化数据段mov ax, stackmov ss, axmov sp, 16mov ax, 4240h   ;ax = 被除数的低16位mov dx, 0Fh     ;dx = 被除数的高16位mov cx, 0Ah     ;cx = 除数call divdwmov ax, 4c00hint 21h;1000000/10(F4240h/0Ah) = int(H/N)*65535 + [rem(H/N)*65535 + L]/N;名称: divdw;功能: 进行不会产生溢出的除法运算,被除数为 dword 型,除数为 word 型,结果为 dword 型;参数: (ax) = dword 型数据的低16位;      (dx) = dword 型数据的高16位;      (cx) = 除数;返回: (ax) = 结果的低16位,(dx) = 结果的高16位;      (cx) = 结果的余数
divdw:push si         ;保存原sipush ax         ;被除数的低16位push dx         ;被除数的高16位;int(H/N)*65535pop ax          ;被除数的高16位mov dx, 0div cx          ;16位除法,被除数为32位,ax存放被除数的低16位,dx存放被除数的高16位;结果的商存在ax,结果的余存在dxmov si, ax      ;si暂存最后结果的高16位,最后要还原到dx寄存器中的;[rem(H/N)*65535 + L]/N     ;上一个除法,已经将rem(H/N)*65535放在dx寄存器中了pop ax          ;被除数的低16位, 也就是公式中的 Ldiv cx          ;16位除法,被除数为32位,ax存放被除数的低16位,dx存放被除数的高16位;结果的商存在ax,结果的余存在dxmov cx, dx      ;余数入cxmov dx, si      ;高16位入dxpop si          ;还原原siretcode ends
end start

我们知道,1000000/10 的商为 100000 = 186A0h,余数为 0,程序执行的结果为:ax = 86A0h,dx = 1,cx = 0,所以我们的程序代码是正确的。

三. 数值显示

1. 需求

        编程,将data段中的数据以十进制的形式显示出来

data segment

        dw 123, 12666, 1, 8, 3, 38

data ends

2. 分析

(1)根据书中材料,我们可以知道,字符'0' ~ '9'的assii码为30h ~ 39h,所以对于数字0 ~ 9,他们对应的字符的assii码为:数字的值 + 30h

(2)对于一个数字,比如:12666,对这个数字循环取余,直到余数为0时,就可以得到每这个数字所有的数码:1,2,6,6,6,对每个数码 + 30h得到每个数码对应的字符的assii码从而得到对应的字符串。然后通过需求一:显示字符串的show_str子程序显示在显示器上。

3.代码

assume cs:code, ds:data, ss:stack
stack segmentdb 32 dup (0)
stack ends
data segmentdb 10 dup (0)
data endscode segment
start:mov ax, stackmov ss, axmov sp, 32mov ax, datamov ds, axmov ax, 12666mov si, 0call dtocmov dh, 8mov dl, 3mov cl, 2mov si, 0call show_strmov ax, 4c00hint 21h;名称:dtoc
;功能:将dword型数据转为表示十进制数的字符串,字符串以 0 为结尾
;参数:(ax) = dword 型数据
;     (ds:si)指向字符串的首地址
;返回:无
dtoc:      mov bx, 0         ;bx用来记录数字的总数码数,比如12666有5个mov di, 10        ;十进制数
loop_dtoc:mov dx, 0         ;16位除法,被除数的低16位在ax,被除数的高16位为0div di            ;16位除法,结果的商在ax中,余数在dx中mov cx, dx        ;余数入cxjcxz ok_dtoc      ;cx = 0,则跳转到标号处执行,否则继续顺序往下执行add dx, 30h       ;数字+30h = 数字对应的字符的assii值push dx           ;字符入栈inc bxloop loop_dtoc
ok_dtoc:mov cx, bx
char_nums:pop axmov ds:[si], al         ;因为assii码的值不会大于255的,所以用 alinc si                  ;ds:si指向下一个字符单元loop char_numsmov byte ptr ds:[si], 0 ;字符串以0结尾  ret ;名称:show_str
;功能:在指定的位置,用指定的颜色,显示一个以0结尾的字符串
;参数:dh=行号(取值范围:0-24),dl=列号(取值范围:0-79)
;      cl=颜色,ds:si指向字符串的首地址
;返回值:无
show_str:;B8000h-BFFFFh共32kb,是80 * 25彩色字符模式的显示缓冲区,每页4kb(4000字节),显示器可以显示任意一页的内容。;一般情况下,显示第0页的内容, 也就是说,B8000h ~ B8F9Fh 这4000个字节的内容会显示在显示器上。每行80个字,;每个字占2个字节,低字节存放字符的assii码,高字节为属性字节。所以每行占160个字节mov ax, 0B800h  ;显示缓冲区段地址mov es, ax;行mov al, 160     ;每行160个字节mul dh          ;8位乘法,一个数默认在al中,另一个在dh中,结果放在ax中mov bx, ax      ;行偏移字节;列mov al, 2       ;一个字占2个字节,低字节存放字符的assii码,高字节为属性字节mul dl          ;8位,乘法,一个数默认在al中,另一个在dl中,结果放在ax中add bx, ax      ;行偏移字节 + 列偏移字节 = 相对于显示缓冲区段地址总的偏移地址mov ch, 0mov dl, cl      ;循环中需要用到cx寄存器,所以把存放字体属性的字节存放在dl中
loop_show_str:mov cl, ds:[si]jcxz ok_show_str        ;cx = 0,跳转到标号处执行,否则,继续顺序往下执行mov es:[bx], clmov es:[bx+1], dlinc siadd bx, 2loop loop_show_strok_show_str:    ret
code ends
end start

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 设计者模式:深度解析及应用
  • DC-DC 转换器中的压电谐振器:当前状态和限制
  • Ps:首选项 - 性能
  • RabbitMQ集群 - 普通集群搭建、宕机情况
  • 控制阶段在DMAIC中的主要目标是什么?
  • python 速成指南
  • vba发邮件的几种方法:新人如何快速上手?
  • OpenCV几何图像变换(1)映射转换函数convertMaps()的使用
  • 前端算法 | LeetCode第 70 题爬楼梯问题
  • 骑行耳机品牌前五名排行榜:5大优质骑行耳机闭眼入都不踩雷!
  • 哈佛大学年中回顾2024年ESG发展近况
  • 导出word格式的Javadoc(可用于快速生成项目详细设计文档)
  • Swoole 和 Java 哪个更有优势呢
  • 白骑士的HTML教学高级篇 3.4 性能优化
  • 音频分割怎么弄?手把手教会你实用的音频分割技巧
  • [译]CSS 居中(Center)方法大合集
  • 【node学习】协程
  • 【React系列】如何构建React应用程序
  • 【跃迁之路】【477天】刻意练习系列236(2018.05.28)
  • CSS选择器——伪元素选择器之处理父元素高度及外边距溢出
  • C语言笔记(第一章:C语言编程)
  • java 多线程基础, 我觉得还是有必要看看的
  • java第三方包学习之lombok
  • Java新版本的开发已正式进入轨道,版本号18.3
  • js 实现textarea输入字数提示
  • Mithril.js 入门介绍
  • Nacos系列:Nacos的Java SDK使用
  • PaddlePaddle-GitHub的正确打开姿势
  • Python 使用 Tornado 框架实现 WebHook 自动部署 Git 项目
  • SSH 免密登录
  • vue从创建到完整的饿了么(18)购物车详细信息的展示与删除
  • 阿里云前端周刊 - 第 26 期
  • 全栈开发——Linux
  • 说说动画卡顿的解决方案
  • 在electron中实现跨域请求,无需更改服务器端设置
  • ​人工智能书单(数学基础篇)
  • ‌JavaScript 数据类型转换
  • ### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLTr
  • ### Error querying database. Cause: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException
  • $L^p$ 调和函数恒为零
  • (2)STL算法之元素计数
  • (ros//EnvironmentVariables)ros环境变量
  • (SERIES12)DM性能优化
  • (动态规划)5. 最长回文子串 java解决
  • (附源码)springboot金融新闻信息服务系统 毕业设计651450
  • (附源码)计算机毕业设计ssm电影分享网站
  • (四)搭建容器云管理平台笔记—安装ETCD(不使用证书)
  • (一)SpringBoot3---尚硅谷总结
  • (转)Mysql的优化设置
  • (转)视频码率,帧率和分辨率的联系与区别
  • ***检测工具之RKHunter AIDE
  • .net 4.0发布后不能正常显示图片问题
  • .net core使用EPPlus设置Excel的页眉和页脚
  • .Net mvc总结
  • .NET 应用架构指导 V2 学习笔记(一) 软件架构的关键原则