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

news2024/9/22 9:44:28

一. 显示字符串

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 segment
    db 'welcome to masm!',0
data ends
code segment
start:
    mov ax, data
    mov ds, ax

    mov dh, 8
    mov dl, 3
    mov cl, 2   ;字属性字节
    mov si, 0
    call show_str

    mov ax, 4c00h
    int 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, 0
    mov dl, cl      ;循环中需要用到cx寄存器,所以把存放字体属性的字节存放在dl中
s:
    mov cl, ds:[si]
    jcxz ok         ;cx = 0,跳转到标号处执行,否则,继续顺序往下执行
    mov es:[bx], cl
    mov es:[bx+1], dl
    inc si
    add bx, 2
    loop s
     
ok:    
    ret

code 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, stack
    mov ss, ax
    mov sp, 16

    mov ax, 4240h   ;ax = 被除数的低16位
    mov dx, 0Fh     ;dx = 被除数的高16位
    mov cx, 0Ah     ;cx = 除数

    call divdw

    mov ax, 4c00h
    int 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         ;保存原si
    push ax         ;被除数的低16位
    push dx         ;被除数的高16位

    ;int(H/N)*65535
    pop ax          ;被除数的高16位
    mov dx, 0
    div cx          ;16位除法,被除数为32位,ax存放被除数的低16位,dx存放被除数的高16位
                    ;结果的商存在ax,结果的余存在dx
    mov si, ax      ;si暂存最后结果的高16位,最后要还原到dx寄存器中的

    ;[rem(H/N)*65535 + L]/N     ;上一个除法,已经将rem(H/N)*65535放在dx寄存器中了
    pop ax          ;被除数的低16位, 也就是公式中的 L
    div cx          ;16位除法,被除数为32位,ax存放被除数的低16位,dx存放被除数的高16位
                    ;结果的商存在ax,结果的余存在dx
    mov cx, dx      ;余数入cx
    mov dx, si      ;高16位入dx
    pop si          ;还原原si

    ret

code 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 segment
    db 32 dup (0)
stack ends
data segment
    db 10 dup (0)
data ends

code segment
start:
    mov ax, stack
    mov ss, ax
    mov sp, 32

    mov ax, data
    mov ds, ax

    mov ax, 12666
    mov si, 0
    call dtoc

    mov dh, 8
    mov dl, 3
    mov cl, 2
    mov si, 0
    call show_str

    mov ax, 4c00h
    int 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位为0
    div di            ;16位除法,结果的商在ax中,余数在dx中
    mov cx, dx        ;余数入cx
    jcxz ok_dtoc      ;cx = 0,则跳转到标号处执行,否则继续顺序往下执行
    add dx, 30h       ;数字+30h = 数字对应的字符的assii值
    push dx           ;字符入栈
    inc bx
    loop loop_dtoc
ok_dtoc:
    mov cx, bx
char_nums:
    pop ax
    mov ds:[si], al         ;因为assii码的值不会大于255的,所以用 al
    inc si                  ;ds:si指向下一个字符单元
    loop char_nums
    mov 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, 0
    mov dl, cl      ;循环中需要用到cx寄存器,所以把存放字体属性的字节存放在dl中
loop_show_str:
    mov cl, ds:[si]
    jcxz ok_show_str        ;cx = 0,跳转到标号处执行,否则,继续顺序往下执行
    mov es:[bx], cl
    mov es:[bx+1], dl
    inc si
    add bx, 2
    loop loop_show_str
     
ok_show_str:    
    ret
code ends
end start

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

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

相关文章

【目标检测】Transformers在小目标检测中的应用:最新技术的基准测试和调查

《Transformers in Small Object Detection: A Benchmark and Survey of State-of-the-Art》 Transformers在小目标检测中的应用:最新技术的基准测试和调查 原文:https://arxiv.org/abs/2309.04902 1 研究背景和目的 小目标检测(SOD&#x…

calico安装

3.20 版本 https://blog.csdn.net/weixin_42094245/article/details/131633980 手动创建了/var/lib/calico/nodename 手动更新了这2个资源 ll /etc/cni 摆烂了 装个3.8.0的 curl 172.30.30.64:32568 curl: (7) Failed connect to 172.30.30.64:32568; Connection timed o…

修复线上问题,又造成了个Bug

项目场景 这是一位朋友给我分享的实际线上问题,看似简单却害了项目再次造出一个bug来。 场景:线上环境中,需要查询某某业务数据,条件是状态,之前产品只要求查两个状态的,但现在让他再多查一个状态的。 自…

编程思维模式比编程语言内容等更重要也更难传授-2024-机器人篇

历程 在2015年起步,然后不断迭代更新优化。 2019:机器人编程实践-ROS2基础与应用- 第四版纲要 里面的重点就是机器人编程的方法论! 2022:机器人编程实践-ROS2基础与应用-第⑦版 2022:ROS2机器人编程实践基础与应用…

macOS系统(intel)编译MAVSDK安卓平台so库

1.克隆mavsdk源码: git clone https://github.com/mavlink/MAVSDK.git --recursive 生成makefile前先手动修改protobuf版本为最新的(如:27.3) 下载的与你安装的版本要一致: 手动编译并安装libLZMA与openssl 如proto文件有修改,需要手动运行 ./tools/generate_from_protoc.sh重…

9 正则表达式:Java爬虫和正则表达式、String中的正则表达式方法(基本语法7)

文章目录 前言一、正则表达式1 [ ] 语法(1)[ABC] 和 [^ABC](2)[A-Z]和[a-zA-Z]小总结2 特殊字符语法(\w 这些)3 数量符4 \ 、()、 |5 锚点 ^ 和 $,\b,\B6 (?i) : 忽略其后面的大小写 ---- 这个Java是可以的,其他语言我不知道(正则表达式虽然大多通用,但也有部分是…

2018年高教社杯全国大学生数学建模竞赛(ABCD题)题目及附件

数学建模练习,老师发了一个2018年的C题论文,让我们复现,结果找题目附件找好长时间,都是泪……好在最后找到了,给大家分享一下。 2018年的数学建模C题不知道官网的链接打不开了已经,找附件找了好长时间………

第1章-03-VS Code开发工具安装

🏆作者简介,黑夜开发者,CSDN领军人物,全栈领域优质创作者✌,CSDN博客专家,阿里云社区专家博主,2023年CSDN全站百大博主。 🏆数年电商行业从业经验,历任核心研发工程师,项目技术负责人。 🏆本文已收录于专栏:Web爬虫入门与实战精讲。 🎉欢迎 👍点赞✍评论⭐收…

智能微气候:精准调控背后的算法革命

( 于景鑫 国家农业信息化工程技术研究中心)当人工智能遇见现代农业,会擦出怎样的火花?随着数字农业、智慧农业的蓬勃发展,人工智能技术正以前所未有的速度渗透到农业生产的方方面面。其中,以深度学习为代表的前沿算法,尤其是大语言模型(LLM),正在成为驱…

【实战教程】一键升级CentOS 7.9.2009至OpenSSL 1.0.2u:加固你的Linux服务器安全防线!

文章目录 【实战教程】一键升级CentOS 7.9.2009至OpenSSL 1.0.2u:加固你的Linux服务器安全防线!一、 背景二、 升级步骤2.1 检查 OpenSSL 版本2.2 安装 OpenSSL 依赖包2.3 下载 OpenSSL 的新版本2.4 解压缩下载的文件2.5 编译并安装 OpenSSL2.5.1 切换到…

Android Forensics with Belkasoft

本课程专为需要在工作中处理 Android 设备并希望增强知识并获得 Android 获取和分析实践经验的数字取证调查员而设计。 您将学到什么? 如何使用Android采集的基本和高级方法,例如基于ADB和APK降级采集 可以使用哪些特定于芯片组的采集方法 如何分析 Andr…

Android实战:实现注册界面

目录 前言 布局图 实现过程 1.导入图片 2.创建分割线样式 3.创建文本样式 4.创建输入框样式 5.XML布局文件 测试 6.实现注册功能 前言 在前面,我们已经学习了一些常见的界面布局和界面控件,那么本篇我们就来结合前面所学的知识,来…

导入导出常见的空指针异常NULLPointException

使用row.getCell()方法去判断是否为空 若不为空再获取 不确定excel文件里的单元格类型 可以使用row.getCell().getCellTypeEnum() 去判断是什么类型 若要把从数据库查询出来的数据导出到excel表格中 要先判断内容是否为空

Spring Boot + MyBatis-Plus 实现 MySQL 主从复制动态数据源切换

Spring Boot MyBatis-Plus 实现 MySQL 主从复制动态数据源切换 一、前言1. 添加依赖2. 配置主从数据源3. 创建数据源配置类4. 创建数据源上下文5. 定义数据源类型6. 配置数据源切换7. 创建DynamicDataSourceConfig8. 创建DynamicRoutingDataSource9. 创建注解10. 使用注解 一、…

1.Java:集合

集合作用: 1.动态保存任意多个对象。 2.提供操作对象方法比如add,remove,set,get等方法。 3.使用集合添加,删除代码简洁。 集合分类 集合分为单列集合以及双列集合。 单列集合: 双列集合: Collection接口特点 1.Collection…

【Nginx】 Nginx Rewrite 相关功能

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

智慧环卫与智慧城市:以人文本的创新发展之路

智慧环卫与智慧城市:以人文本的创新发展之路 前言智慧环卫与智慧城市 前言 智慧环卫和智慧城市的建设是当今社会发展的重要趋势,它们对于提升城市管理水平、改善居民生活质量具有至关重要的意义。随着国家政策对新型城市建设的大力推动,智慧…

学习 node.js 六 Markdown 转为 html,zlib

目录 Markdown 转为 html 安装 ejs语法 标签含义 1. 纯文本标签 2. 输出经过 HTML 转义的内容 3. 输出非转义的内容(原始内容) marked browserSync zlib gzip deflate gzip 和 deflate 区别 http请求压缩 Markdown 转为 html 什么是markdown? Markdo…

数据库系列之GaussDB数据库高可用部署方案

GaussDB数据库主备架构的基本组件,以及基于华为云底座和轻量化部署TPOPS两种方式的典型高可用部署场景介绍。 1、GaussDB数据库组件 1.1 GaussDB数据库集中式主备集群基本组件 CM由CM Agent、CM Server和OM monitor构成: CM Agent:管理服务组件,由OMM拉起(周期1秒),主要…

ARM32开发——PWM高级定时器

🎬 秋野酱:《个人主页》 🔥 个人专栏:《Java专栏》《Python专栏》 ⛺️心若有所向往,何惧道阻且长 文章目录 需求高级定时器通道互补输出开发流程通道配置 打开互补保护电路完整代码 需求 点亮2个灯,采用互补pwm的方式 高级定时…