《汇编语言》- 读书笔记 - 实验 10 编写子程序

《汇编语言》- 读书笔记 - 实验 10 编写子程序

  • 1. 显示字符串
    • 问题
    • 子程序描述 show_str
    • 提示
    • 结果
    • 演示
  • 2. 解决除法溢出的问题
    • 问题
    • 子程序描述 divdw
    • 提示
    • 结果
    • 演示
  • 3. 数值显示
    • 问题
    • 子程序描述 dtoc
    • 提示
    • 结果
    • 演示

在这次实验中,我们将要编写3个子程序,通过它们来认识几个常见的问题和掌握解决这些问题的方法。同前面的所有实验一样,这个实验是必须独立完成的,在后面的课程中,将要用到这个实验中编写的3个子程序。

1. 显示字符串

问题

显示字符串是个常用功能,写个子程序来实现此功能。子程序要支持参数:显示的位置(行、列)、内容和颜色。

子程序描述 show_str

名称:show_str
功能:在指定的位置,用指定的颜色,显示一个用0结束的字符串。
参数:(dh) = 行号(取值范围 0~24),
(dl) = 列号(取值范围 0~79),
(cl) = 颜色,ds:si 指向字符串的首地址
返回:
应用举例:在屏幕的83列,用绿色显示data段中的字符串

提示

  1. 子程序的入口参数是屏幕上的行号和列号,注意在子程序内部要将它们转化为显存中的地址,首先要分析一下屏幕上的行列位置和显存地址的对应关系;
  2. 注意保存子程序中用到的相关寄存器;
  3. 这个子程序的内部处理和显存的结构密切相关,但是向外提供了与显存结构无关的接口。通过调用这个子程序,进行字符串的显示时可以不必了解显存的结构,为编程提供了方便。在实验中,注意体会这种设计思想。

结果

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

code segment
 start:	mov dh,8		;8 行
		mov dl,3		;3 列
		mov cl,2		; 颜色
		mov ax,data		; 设置数据段
		mov ds,ax
		mov si,0		; 指向字符串首地址
		call show_str	; 调用子程序
		
		mov ax,4c00h	; 退出
		int 21h
; ------------------- 子程序 -------------------
show_str:				
		push si				; 缓存寄存器
		push di
		push es
		push dx
		push cx
		push bx
		push ax

		mov ax,0B800h	; 设置显存段地址
		mov es,ax
		
		mov al,160		; 先算行偏移
		dec dh				; 行号从 0 开始,所以这里要先减1
		mul dh				; 行数 x 160算出行偏移
		mov bx,ax			; 行偏移先存到 bx
		mov al,2		; 再算列偏移
		dec dl				; 列号从 0 开始,所以这里要先减1
		mul dl
		add bx,ax		;+= 算出目标字符串(显存)的开始位置

		mov dl,cl 		; 字符属性换个地方存。cx下面要用来循环
		mov ch,0		; cx高位清空(后面我们只改 cl,就方便 jcxz 判断了)
		
		mov di,0		; 指向目标字符串首字符
		
 sloop:	mov cl,ds:[si]		; 取字符
		mov es:[bx+di],cl	; 字符写入显存
		mov es:[bx+di+1],dl ; 字符属性写入显存
		jcxz ok				; 如果为 0 字符结束,跳出循环
		inc si				; si 递增,源字符串指向下一字符
		add di,2			; di += 2,目标字符串指向下一字符
		jmp short sloop
	ok:	
		pop ax			; 还原寄存器
		pop bx
		pop cx
		pop dx
		pop es
		pop di
		pop si
		ret
; ------------------- 子程序 -------------------
code ends
end start

演示

在这里插入图片描述

2. 解决除法溢出的问题

问题

div指令执行除法时:
8位除法的AL = 商AH = 余数
16位除法则分别用AXDX存储余数
但若结果超出ALAX的最大范围,该如何处理?

比如:
8位除法:FFFF ÷ 1al 中容纳不下商 FFFFh
16位除法:10000h ÷ 1ax 中容纳不下商 1 0000h

为解决这一问题,我们设计一个子程序来专门处理它。

子程序描述 divdw

名称:divdw
功能:进行不会产生溢出的除法运算,被除数dword 型,除数word 型,结果dword 型。
参数:(ax) = dword被除数 16 位,
(dx) = dword被除数 16 位,
(cx) = 除数
返回:(ax) = 结果的低16位
(dx) = 结果的高16位
(cx) = 余数
应用举例:计算:1000000/10(F4240H/0AH)
结果:(dx)=0001H, (ax)=86A0H, (cx)=0

提示

书中给出的公式:

公式X/N = int(H/N) * 65536 + [ rem(H/N) * 65536 + L ] / N
X被除数,范围:[0,FFFFFFFF]
N除数,范围:[0,FFFF]
HX 高 16 位,范围:[0,FFFF]
LX 低 16 位,范围:[0,FFFF]
int()描述性运算符,取商,比如,int(38/10)=3
rem()描述性运算符,取余数,比如,rem(38/10)=8

这个公式将可能产生溢出的除法运算:XN,转变为多个不会产生溢出的除法运算。公式中,等号右边的所有除法运算都可以用 div 指令来做,肯定不会导致除法溢出。
(关于这个公式的推导,有兴趣的读者请参看附注5。)

结果

assume cs:code
code segment
 start:	mov ax,4240h	; dword 被除数的低 16位
		mov dx,000Fh	; dword 被除数的高 16位
		mov cx,0Ah		; word  除数
		call divdw		; 调用子程序 dword 类型除法
		
		mov ax,4c00h	; 退出
		int 21h
; ------------------- 子程序 -------------------
divdw:
		push si		; 缓存寄存器
		push bx

		mov si,ax	; 因为要用到 ax,所以被除数的低 16位,临时放在 si
		mov ax,dx	; 先算高 16 位
		mov dx,0		;160
		div cx			; 除数16位,则被除数32位。商ax,余dx
		mov bx,ax		; 临时保存高16位商
		
		mov ax,si	; 后算低 16;16位的余数留在 dx不用动。相当于:余数 * 10000 +16位
		div cx			; 除数16位,则被除数32位。商ax,余dx
		mov cx,dx	; 得到余数
		mov dx,bx	; 拿回临时保存的高16位商
	
		pop bx		; 还原寄存器	
		pop si
		ret
; ------------------- 子程序 -------------------
code ends
end start

演示

在这里插入图片描述

3. 数值显示

问题

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

data seqment
	dw 123,12666,1,8,3,38
data ends

但是数据在内存中都是二进制信息,
比如 12666 在内存保存的是二进制的0011 0001 0111 1010等于16进制317A

可见,要将数据用十进制形式显示到屏幕上,要进行两步工作:

  1. 将用二进制信息存储的数据转变为十进制形式的字符串。(我们需要设计一个子程序)
  2. 显示十进制形式的字符串。(这个我们可以前面设计 好的 show_str

子程序描述 dtoc

名称:dtoc
功能:word 型数据转变为表示十进制数的字符串,字符串以0为结尾符。
参数:(ax) = word 型数据
ds:si 指向字符串的首地址
返回:
应用举例编程,将数据12666十进制的形式在屏幕的8行3列,用绿色显示出来。
在显示时我们调用本次实验中的第一个子程序 show str

提示

  1. 十进制数码字符对应的ASCII码 = 十进制数码值 + 30H
    12666 对应:
12666
31H32H36H36H36H
  1. 要求得 12666 的每一位是多少,可以用除法迭代取数:
    在这里插入图片描述
  2. 借助 jcxz 指令,用是否为 0 作为循环结束的条件。
  3. 按这个顺序取余得到的是 66621 最后我们还要把它翻转过来才是 12666

结果

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

code segment
 start:	
		mov bx,data		; 设置段地址
		mov ds,bx
						; 调用子程序 dtoc 将 word 转 10 进制数字
		mov ax,12666		; word 型数据
		mov si,0			; 循环变量从 0 开始
		call dtoc		
		
						; 调用子程序 show_str 在屏幕 83列用绿色显示
		mov dh,8
		mov dl,3
		mov cl,2
		call show_str
		
		mov ax,4c00h	; 退出
		int 21h
; ------------------- 子程序 dtoc -------------------
dtoc:
		push si		; 缓存寄存器
		push di
		push bx
		
	; 用遍历取余的方式拿到 ascii 拿到的结果是倒的
	; 比如 12666 遍历取余拿到的是 66621 所以先丢栈里,方便下一步翻转
		mov bx,10
	s:	mov dx,0	; 除数 bx 是 16 位,则被除数是32位。高16位 dx 没有数据要补 0
		div bx		; 除完后 商在ax下次继续用,dx为余数
		add dx,30H	; 将余数转 ascii 
		push dx		; 入栈备用(此时高8位是无意义的,之后我们只要取低8位用即可 )
		inc si		; 循环变量 +1
		mov cx,ax	; 取商来判断是否为 0
		jcxz s_ok		; 如果商为0跳出循环
		jmp s			; 否则继续循环
 s_ok:
	; 目前栈里是 66621 顺序不是我们想要的,遍历一下出栈到 ds:[0]... 就正了
		mov di,0
	r:	pop ax
		mov [di],al	; 写入目标内存地址。第 di 个字符(我们只取低8位有效值)
		inc di
		dec si
		mov cx,si	; 出栈到第 si 个
		jcxz r_ok		; 如果 si 为 0 表示出完,结束循环
		jmp r			; 否则继续出栈
 r_ok:	
		pop bx		; 还原寄存器
		pop di
		pop si
		ret
; ------------------- 子程序 dtoc -------------------
; ------------------- 子程序 show_str -------------------
show_str:				
		push si				; 缓存寄存器
		push di
		push es
		push dx
		push cx
		push bx
		push ax

		mov ax,0B800h	; 设置显存段地址
		mov es,ax
		
		mov al,160		; 先算行偏移
		dec dh				; 行号从 0 开始,所以这里要先减1
		mul dh				; 行数 x 160算出行偏移
		mov bx,ax			; 行偏移先存到 bx
		mov al,2		; 再算列偏移
		dec dl				; 列号从 0 开始,所以这里要先减1
		mul dl
		add bx,ax		;+= 算出目标字符串(显存)的开始位置

		mov dl,cl 		; 字符属性换个地方存。cx下面要用来循环
		mov ch,0		; cx高位清空(后面我们只改 cl,就方便 jcxz 判断了)
		
		mov di,0		; 指向目标字符串首字符
		
 sloop:	mov cl,ds:[si]		; 取字符
		mov es:[bx+di],cl	; 字符写入显存
		mov es:[bx+di+1],dl ; 字符属性写入显存
		jcxz ok				; 如果为 0 字符结束,跳出循环
		inc si				; si 递增,源字符串指向下一字符
		add di,2			; di += 2,目标字符串指向下一字符
		jmp short sloop
	ok:	
		pop ax			; 还原寄存器
		pop bx
		pop cx
		pop dx
		pop es
		pop di
		pop si
		ret
; ------------------- 子程序 show_str -------------------
code ends
end start

演示

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

UE蓝图 分支(Branch)节点和源码

系列文章目录 UE蓝图 Get节点和源码 UE蓝图 Set节点和源码 UE蓝图 Cast节点和源码 UE蓝图 分支(Branch)节点和源码 文章目录 系列文章目录一、分支节点功能二、分支节点用法三、分支节点使用场景四、分支节点实现过程五、分支节点相关源码 一、分支节点功能 在Unreal Engine&a…

QGis软件 —— 6、QGis - 线与点相互转化操作

线转为点 1、创建一条线 2、对线用点进行分割,由于下图单位是"度" 那么需要对该图层做重投影。 3、对线做"重投影图层"操作 4、对线用点进行分割 点转为线 将点转为线,如下动图。通常用作于外出人员采集gps点后通过csv文件导入qgis&…

ChatGPT-01 用ChatGPT指令,自学任何领域的系统知识

1. 指令位置 Github仓库:Mr Ranedeer AI Tutor 但是需要开通chatgtp plus版本,并且打开代码解释器 2 使用 学习内容 开始学习 GPT甚至可以给你思考题,给出的答案还能进行评价 配置 通过配置表修改 深度 学习风格 沟通风格 语气风格 …

【Python机器学习】详解Python机器学习进行时间序列预测

🔗 运行环境:Python 🚩 撰写作者:左手の明天 🥇 精选专栏:《python》 🔥 推荐专栏:《算法研究》 🔐#### 防伪水印——左手の明天 ####🔐 💗 大家…

适合tiktok运营的云手机需要满足什么条件?

TikTok作为一款全球热门的社交媒体平台,具有无限的市场潜力。然而,卖家在运营过程中常常会面临到视频0播、账号被降权、限流等问题,甚至可能因为多人同时使用一个IP而导致封号的风险。为了规避这些问题,越来越多的卖家将目光投向了…

领先一步:2024年大广赛设计趋势预测

2024年大赛已经开始!作为最具影响力的学科竞赛项目之一,中国大学生好创意全国大学生广告艺术大赛(以下简称“大广赛”)自2005年以来已举办12届13届大赛,是权威机构认可的以“创意”为核心理念、以“创新”为教育目标的…

JavaScript数据类型学习脑图

字符串(String)、数字(Number)、布尔(Boolean)、数组(Array)、对象(Object)、空(Null)、未定义(Undefined)

红队学习笔记Day6 --->干货分享

今天看到这样的一个东西,好好好,有点恐怖😓😓😱😱😱😱 我就想网安是不是也有这种东西? 我来试试 icmp,RDP,arp,dhcp,nat&a…

Unity基于AssetBundle资源管理流程详解

在Unity游戏开发中,资源管理是一个非常重要的环节。随着游戏的发展,资源会变得越来越庞大,因此需要一种高效的资源管理方式来减少内存占用和加快加载速度。AssetBundle是Unity提供的一种资源打包和加载方式,可以将资源打包成一个独…

GIS分析-绘制土壤水分图

土壤水分是水文循环的一个重要单元,影响着地下水补给(或深层渗透)和地表径流的水量。此外,土壤水分分析在评估土地退化、荒漠化和洪水方面也发挥着至关重要的作用。土壤水分通常是在野外通过定点测量来确定的,但这种方法虽然结果准确,但却费力费钱。在本研究中,我们将通…

vue3实现瀑布流布局组件

先看效果图 直接上代码 utils.js // 用于模拟接口请求 export const getRemoteData (data 获取数据, time 2000) > {return new Promise((resolve) > {setTimeout(() > {console.log(模拟获取接口数据, data)resolve(data)}, time)}) }// 获取数组随机项 export…

App启动优化笔记 1

app大致的启动流程。有Launcher进程,system_server进程,zygote进程,APP进程。 Launcher进程:启动activity来启动应用 system_server进程:(ams是其中的一个binder):发送一个socket消息给Zygote。 zygote进程:收到消息后,fork新的进程,---》app进程启动 APP进程:…

TRIZ理论下的新能源电机革新之路

随着全球能源结构的转型和环保理念的深入人心,新能源电机作为绿色能源的重要组成部分,正受到越来越多的关注。本文将从TRIZ理论的角度出发,探讨新能源电机的创新与发展。 TRIZ,即发明问题解决理论,是一种创新方法论&am…

期刊LaTeX模板下载

文章目录 期刊LaTeX模板下载1.通过overleaf模板库下载2.通过期刊官网下载2.1 IEEE期刊论文LaTeX模板的查找下载2.2 Elsevier期刊论文LaTeX模板的查找下载 期刊LaTeX模板下载 IEEE期刊模板下载地址:https://template-selector.ieee.org/secure/templateSelector/pub…

木头姐2024 重磅产业调研与预测报告(163页)

感兴趣的小伙伴自取: 木头姐2024 重磅产业调研与预测报告(163页)

openGauss 5.0.0全密态数据库应用小试

前言 openGauss HCIA教材中,安全是一个重要的章节,在实际项目中,随着网络安全和信息安全形势的变化,企业也越来越重视数据库安全。去年在HALP内部进行openGauss培训时,安全特性就被学员们提出来要重点讲解&#xff0c…

【4.1计算机网络】TCP-IP协议簇

目录 1.OSI七层模型2.常见协议及默认端口3.TCP与UDP的区别 1.OSI七层模型 osi七层模型: 1.应用层 2.表示层 3.会话层 4.传输层:TCP为可靠的传输层协议。 5.网络层 6.数据链路层 7.物理层 2.常见协议及默认端口 3.TCP与UDP的区别 例题1. 解析&#xff1…

层级关联,审批人功能

一个需求要求选择一级&#xff0c;下方展示一级的效果 后端给了审批人数据&#xff0c;但是数据需要单独处理 <template><div class"box"><el-form :model"ruleForm" :rules"rules" ref"ruleForm" label-width"…

AI新工具(20240219) Ollama Windows预览版;谷歌开源的人工智能文件类型识别系统; PopAi是您的个人人工智能工作空间

Ollama Windows preview - Ollama Windows预览版用户可以在本地创建和运行大语言模型&#xff0c;并且支持NVIDIA GPU和现代CPU指令集的硬件加速 Ollama发布了Windows预览版&#xff0c;使用户能够在原生的Windows环境中拉取、运行和创建大语言模型。该版本支持英伟达的GPU&am…

iOS整理 - 关于直播 - 搭建服务端

前言 其实本人一直都想自己简单做一套直播&#xff08;包括移动端和服务端&#xff09;的开发测试&#xff0c;但是之前一直做得比较迷茫。最近偶然间在来了灵感&#xff0c;瞬间解除了我很多疑惑。我会分享出来&#xff0c;希望大家一起研究下。稍后&#xff0c;我完整做好了…