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

一. 显示字符串

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/51941.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

第六版页面

基本 明确定义 站点网关mqtt服务器 多个柜子使用的是主从模式 下发一个设备组其他的柜子跟着设置 具体的让后端进行详细管理 前端规范 字体规范 弹出框定义什么应该弹出什么不应该弹出 页面 主页 屏幕宽度有的没设置好 平面地图模式有的没重合好 日志改为告警在上面 日志…

cmake install setlocal错误

cmake中的代码如下: #设置安装目录的前缀 set(CMAKE_INSTALL_PREFIX $ENV{PUBLISH_DIR}) #这边的输出满足要求 message(STATUS "install dir:${CMAKE_INSTALL_PREFIX}") #指定安装 install(TARGETS ${TARGET_NAME} RUNTIME DESTINATION bin …

机械学习—零基础学习日志(如何理解概率论3)

随机变量的函数分布 一维随机变量分布,可以看到下图,X为不同情况的概率。而x如果是大于等于X,那么当x在40以内时,没有概率,为0。 当x变大,在40-80之间,那么x大于X的概率为,0.7&…

Liunx搭建Rustdesk远程桌面服务

1、环境准备 Linux:centos7.9 rustdesk server安装包 很多新服务器并没有 wget 和unzip 可以通过yum自行安装下,如果系统中有wget但不能使用,直接卸载重装即可。 yum install wget wget --no-check-certificate https://github.com/rust…

《黑神话悟空》打不开解决方法介绍

黑神话悟空打不开怎么办?很多的玩家都非常的好奇自己的黑神话悟空为什么打不开,这里整理了黑神话悟空打不开解决方法介绍,详细的内容可以在这里进行了解,有需要的小伙伴们一起来看看吧! 解决方法1:验证文件…

Go第一个程序

package mainimport "fmt"func main() {str : "hello go"fmt.Println(str) }上述很简单,如何使用os包获取命令行参数呢? package mainimport ("fmt""os" )func main() {fmt.Println(os.Args)str : "hello…

【Alibaba Cola 状态机】重点解析以及实践案例

【Alibaba Cola 状态机】重点解析以及实践案例 1. 状态模式 状态模式是一种行为型设计模式,允许对象在内部状态改变时改变其行为,简单地讲就是,一个拥有状态的context对象,在不同状态下,其行为会发生改变。看起来是改…

电脑开机LOGO修改教程_BIOS启动图片替换方法

准备工具:刷BIOS神器和change logo,打包下载地址:https://download.csdn.net/download/baiseled/89374686 一.打开刷BIOS神器,点击备份BIOS,保存到桌面 二.打开change logo,1.点击load image,选…

RabbitMQ实现多线程处理接收消息

前言:在使用RabbitListener注解来指定消费方法的时候,默认情况是单线程去监听队列,但是这个如果在高并发的场景中会出现很多个任务,但是每次只消费一个消息,就会很缓慢。单线程处理消息容易引起消息处理缓慢&#xff0…

【Nginx】 Nginx Rewrite 相关功能

Nginx服务器利用 ngx_http_rewrite_module 模块解析和处理rewrite请求 此功能依靠 PCRE(perl compatible regular expression),因此编译之前要安装PCRE库 rewrite是nginx服务器的重要功能之一,用于实现URL的重写,URL的重写是非常有用的功能 比…

【无标题】Image-to-Image Translation 图像风格迁移中的成对图像拼接代码

引 言 在图像风格迁移任务中,近几年比较火热的Generative Adversarial Nets (GAN)模型以及各种变体深受视觉研究团体的青睐,在具体任务中取得比较不错的实验表现。在有监督图像风格迁移任务迁移中,需要输入给模型成对的图片(一个来…

Gaussian Splatting 在 Ubuntu22.04 下部署

代码:graphdeco-inria/gaussian-splatting (github) 论文:[2308.04079] 3D Gaussian Splatting for Real-Time Radiance Field Rendering (arxiv.org) 1. 禁用自带驱动 Nouveau Ubuntu 自带的显卡驱动,是非 Nvida 官方版。在后面装 CUDA 的时候,会报驱动不兼容问题。 1.…

2024关于接口测试自动化的总结与思考!

序 近期看到阿里云性能测试 PTS 接口测试开启免费公测,本着以和大家交流如何实现高效的接口测试为出发点,本文包含了我在接口测试领域的一些方法和心得,希望大家一起讨论和分享,内容包括但不仅限于: 服务端接口测试介…

如何将网站地图Sitemap提交至百度、谷歌及Bing搜索引擎

原文:如何将网站地图Sitemap提交至百度、谷歌及Bing搜索引擎 - 孔乙己大叔 (rebootvip.com) 在当今高度竞争的互联网环境中,搜索引擎优化(SEO)对于网站的可见性和成功至关重要。网站地图(Sitemap)&#xff…

死锁问题分析和解决——资源回收时

1.描述问题 在完成线程池核心功能功能时,没有遇到太大的问题(Any,Result,Semfore的设计),在做线程池资源回收时,遇到了死锁的问题 1、在ThreadPool的资源回收,等待线程池所有线程退出时&#xff…

【Redis】数据类型详解及其应用场景

目录 Redis 常⻅数据类型预备知识基本全局命令小结 数据结构和内部编码单线程架构引出单线程模型为什么单线程还能这么快 Redis 常⻅数据类型 Redis 提供了 5 种数据结构,理解每种数据结构的特点对于 Redis 开发运维⾮常重要,同时掌握每种数据结构的常⻅…

【Oracle篇】统计信息和动态采样的深度剖析(第一篇,总共六篇)

💫《博主介绍》:✨又是一天没白过,我是奈斯,DBA一名✨ 💫《擅长领域》:✌️擅长Oracle、MySQL、SQLserver、阿里云AnalyticDB for MySQL(分布式数据仓库)、Linux,也在扩展大数据方向的知识面✌️…

PostgreSQL-02-入门篇-查询数据

文章目录 1 简单查询SELECT 语句简介SELECT 语句语法SELECT 示例1) 使用 SELECT 语句查询一列数据的示例2) 使用 SELECT 语句查询多列数据的示例3) 使用 SELECT 语句查询表所有列数据的示例4) 使用带有表达式的 SELECT 语句的示例5) 使用带有表达式的 SELECT 语句的示例 2 列别…

MySQL基础:函数

💎所属专栏:MySQL 函数是指一段可以直接被另一段程序调用的程序或代码,在MySQL中也内置了许多函数供开发者去调用,例如之前提到的聚合函数,本节再去介绍一些其他常用的函数 字符串函数 函数功能CONCAT(S1,S2...Sn)字…

可视化编程-七巧低代码入门02

1.1.什么是可视化编程 非可视化编程是一种直接在集成开发环境中(IDE)编写代码的编程方式,这种编程方式要求开发人员具备深入的编程知识,开发效率相对较低,代码维护难度较大,容易出现错误,也需要…