编写子程序

  • 实验内容、程序清单及运行结果
  1. 编写子程序(课本实验10)

1.显示字符串

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

子程序描述

名称:show_str

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

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

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

返回:无

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

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

        mov ds, ax

        mov si, 0

        call show_str

        

        mov ax, 4c00h

        int 21h

show_str:    ;

            ;

            ;

code ends

end start

提示

(1)子程序的入口参数是屏幕上的行号和列号,注意在子程序内部要将它们转化为显存中的地址,

首先要分析一下屏幕上的行列位置和显存地址的对应关系 ;

(2)注意保存子程序中用到的相关寄存器;

(3)这个子程序的内部处理和显存的结构密切相关,但是向外提供了与显存结构无关的接口。

通过调用这个子程序,进行字符串的显示时可以不必了解显存的结构,为编程提供了方便。在实验中,

注意体会这种设计思想。

解:

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

mov ds, ax

mov si, 0

call show_str

mov ax, 4c00h

int 21h

show_str: push ax

push bx

push es

push si

mov ax, 0b800h

mov es, ax

mov  ax, 160

mul dh

mov bx, ax ;bx=160*dh

mov ax, 2

mul dl ;ax=dl*2

add bx, ax ;mov bx, (160*dh + dl*2)设置es:bx指向显存首地址

mov al, cl ;把颜色cl赋值al

mov cl, 0

show0: mov ch, [si]

jcxz show1 ;(ds:si)=0时,转到show1执行

mov es:[bx], ch

mov es:[bx+1], al

inc si ;ds:si指向下一个字符地址

add bx, 2 ;es:bx指向下一个显存地址

jmp show0

show1: pop si

pop es

pop bx

pop ax

ret

code ends

end start

运行结果:

3.数值显示

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

data segment

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

data ends

这些数据在内存中都是二进制信息,标记了数值的大小。要把它们显示到屏幕上,成为我们能够

读懂的信息,需要进行信息的转化。比如,数据12666,在机器中存储为二进制信息:

0011000101111010B(317AH),计算机可以理解它。而要在显示器上读到可以理解的数值12666,

我们看到的应该是一串字符:”12666“。由于显卡遵循的是ASCII编码,为了让我们能在显示器

上看到这串字符,它在机器中应以ASCII码的形式存储为:31H、32H、36H、36H、36H(字符

”0“~”9“对应的ASCII码为30H~39H)。

通过上面的分析可以看到,在概念世界中,有一个抽象的数据12666,它表示了一个数值的大小。

在现实世界中它可以有多种表示形式,可以在电子机器中以高低电平(二进制)的形式存储,

也可以在纸上,黑板上、屏幕上以人数的语言”12666“来书写。现在,我们面临的问题就是,

要将同一抽象的数据,从一种表示形式转化为另一种表示形式。

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

(1)将用二进制信息存储的数据转变为十进制形式的字符串;

(2)显示十进制形式的字符串。

第二步我们在本次实险的第一个子程序中已经实现,在这里只要调用一下show_str即可。我们来㢑第一步,

因为将二进制信息转变为十进制形式的字符串也是经常要用到的功能,我们应该为它编写一个通用的子程序。

子程序描述

名称:dtoc

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

参数:(ax)=word型数据

      ds:si指向字符串的首地址

返回:无

应用举例:编程,将数据12666以十进制的形式在屏幕的8行3列,用绿色显示出来。在显示

时我们调用本次实验中的第一个子程序show_str。

assume cs:code

data segment

    db 10 dup (0)

data ends

code segment

 start:    mov ax, 12666

        mov bx, data

        mov ds, bx

        mov si, 0

        call dtoc

        

        mov dh, 8

        mov dl, 3

        mov cl, 2

        call show_str

        :

        :

        :

code ends

end start

提示

下面我们对这个问题进行一下简单地分析。

(1)要得到字符串”12666“,就是要得到一列表示该字符串的ASCII码:31H、32H、36H、36H、36H。

十进制数码字会对应的ASCII码=十进制数据码值+30H。

要得到表示十进制数的字符串,先求十进制数每位的值。

例:对于12666,先求得每位的值:1、2、6、6、6。再将这些数分别加上30H,便得到了表示12666的

ASCII码串:31H、32H、36H、36H、36H。

(2)那么,怎样得到每位的值呢?采用下面的方法:

可见,用10除12666,共除5次,记下每次的余数,就得到了每位的值。

(3)综合以上分析,可得出处理过程如下。

用12666除以10,循环5次,记下每次的余数:将每次的余数分别加30H,便得到了表示

;问题:编程,将data段中的数据以十进制的形式显示出来。 db:字节型数据  dw:字型数据  dd:双字型数据

assume cs:code,ds:data

data segment 

db 10 dup (0)

data ends 

code segment 

start: mov ax,12666

mov bx,data

mov ds,bx

mov si,0 ;ds:si指向data首地址

call dtoc1

mov dh,8

mov dl,3

mov cl,2

call show_str

mov ax,4c00h

int 21h

;名称:dtoc1

;功能:将word型数据转变为表示十进制的字符串

;参数:(ax)=word型数据;

;ds:si指向字符串首地址

;返回:无。

dtoc1: push ax

push bx

push cx

push dx

push si

push di

mov di,0

d10: mov dx,0 ;设置被除数高位为0

mov bx,10 ;除数为10

div bx

add dx,30h ;ax/10的余数+30H,转为字符

push dx ;字符入栈

inc di ;记录字符个数

mov cx,ax

jcxz dll ;当ax/10的商=0时,转到dll执行

jmp d10

dll: mov cx,di

d12: pop dx ;字符出栈

mov [si],dl

inc si ;ds:si指向下一单元

loop d12

mov dl,0

mov [si],dl ;设置结尾符0

pop si

pop di

pop dx

pop cx

pop bx

pop ax

ret

;名称:show_str

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

;参数:(dh)=行号(取值范围0~24);

;      (dl)=列号(取值范围0~79);

;      (cl)=颜色;

;      ds:si指向字符串的首地址。

;返回:无。

show_str: push ax

push bx

mov ax,0b800h

mov es,ax

mov ax,160

mul dh

mov bx,ax ;bx=160*dh

mov ax,2

mul dl ;ax=dl*2

add bx,ax ;mov bx,(160*dh+dl*2)设置es:bx指向显存首地址

mov al,cl ;把颜色cl赋值al

mov cl,0

show0: mov ch,[si]

jcxz show1 ;(ds:si)=0时,转到show1执行

mov es:[bx],ch

mov es:[bx+1],al

inc si ;ds:si指向下一个字符地址

add bx,2 ;es:bx指向下一个显存地址

jmp show0

show1: pop bx

pop ax

ret

code ends 

end start 

运行结果:

(4)对(3)的质疑

在已知数据是126666的情况下,知道进行5次循环。可在实际问题中,数据的值是多少程序员并不知道,

也就是说,程序员不能事先确定循环次数。

那么,如何确定数据各位的值已经全部求出了呢?我们可以看出,只要是除到商为0,

各位的值就已经全部求出。可以使用jcxz指令来实现相关的功能。

;问题:应用举例:将数据2494967295以十进制的形式在屏幕的8行3列,用绿色显示出来。

assume cs:code,ds:data

data segment 

db 10 dup (0)

data ends 

code segment 

start: mov ax,0ffffh

mov dx,0ffffh

mov bx,data

mov ds,bx

mov si,0 ;ds:si指向data首地址

call dtoc2

mov dh,8

mov dl,3

mov cl,2

call show_str

mov ax, 4c00h

int 21h

;名称:dtoc2

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

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

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

; ds:si指向字符串首地址

;返回:无。

dtoc2:

push ax

push bx

push cx

push dx

push si

push di

mov di,0

d20: mov cx,10 ;除数为10

call divdw

add cx,30h ;余数+30h,转为字符

push cx ;字符入栈

inc di ;记录字符个数

mov cx,ax

jcxz d21 ;低位商=0时,转到d21检测高位商

jmp d20

d21: mov cx,dx

jcxz d22 ;高低位商全=0时,转到d22执行

jmp d20

d22: mov cx,di

d23: pop ax ;字符出栈

mov [si],al

inc si ;ds:si指向下一单元

loop d23

mov al,0

mov [si],al ;设置结尾符0

pop di

pop si

pop dx

pop cx

pop bx

pop ax

ret

;名称:show_str

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

;参数:(dh)=行号(取值范围0~24);

;      (dl)=列号(取值范围0~79);

;      (cl)=颜色;

;      ds:si指向字符串的首地址。

;返回:无。

show_str: push ax

push bx

mov ax,0b800h

mov es,ax

mov ax,160

mul dh

mov bx, ax ;bx=160*dh

mov ax,2

mul dl ;ax=dl*2

add bx,ax ;mov bx,(160*dh+dl*2)设置es:bx指向显存首地址

mov al,cl ;把颜色cl赋值al

mov cl,0

show0: mov ch,[si]

jcxz show1 ;(ds:si)=0时,转到show1执行

mov es:[bx],ch

mov es:[bx+1],al

inc si ;ds:si指向下一个字符地址

add bx,2 ;es:bx指向下一个显存地址

jmp show0

show1: pop bx

pop ax

ret

;名称:divdw

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

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

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

;      (cx)=除数。

;返回:(dx)=结果的高16位;

;      (ax)=结果的低16位;

;      (cx)=余数。

divdw: push si

push bx

push ax

mov ax,dx

mov dx,0

div cx ;被除数的高位/cx

mov si,ax

pop ax

div cx ;(被除数高位的商+低位)/cx

mov cx,dx ;余数入cx

mov dx,si ;高位的商入dx

pop bx

pop si

ret

code ends 

end start 

运行结果:

  1. 编写子程序(课本实验11)

编写一个子程序,将包含任意字符,以 0 结尾的字符串中的小写字母转变成大写字母。描述如下:

名称:letterc

功能:将以 0 结尾的字符串中的小写字母转变成大写字母

参数:ds:si 指向字符串首地址

应用举例:

assume cs:codesg

datasg segment

db "Beginner's All-purpose Symbolic Instruction Code.",0

datasg ends

begin:

mov ax,datasg

mov ds,ax

mov si,0

call letterc

mov ax,4c00h

int 21h

letterc:

;待完成部分

codesg ends

end begin

注:需要进行转化的是字符串中的小写字母 a~z,而不是其他字符。

解:

assume cs:codesg

datasg segment

db "Beginner's All-purpose Symbolic Instruction Code.",0

datasg ends

codesg segment

begin:

mov ax,datasg

mov ds,ax ;段寄存器DS指向datasg段

mov si,0

call letterc ;子程序调用

mov ax,4c00h

int 21h

letterc:

push cx ;将子程序用到的寄存器内容入栈

push si

mov cl,ds:[si] ;取字符串中的字符

jcxz exit ;如果CX等于0则退出

cmp cl,97

jb help ;如果ASCII值小于97则转移至help

cmp cl,122

ja help ;如果ASCII值大于122则转移至help

and cl,11011111b ;通过逻辑与运算将字母转换为大写字母

mov ds:[si],cl ;将转换后的字符重写回对应的内存单元

jmp short help ;转移实现类似循环的功能

help:

inc si ;偏移1个字节取字符

jmp short letterc ;循环

exit:

pop si

pop cx ;将子程序用到的寄存器内容入栈

ret ;子程序返回

codesg ends 

end begin

  1. 编写子程序

名称:strcpy
;功能:将ds:si开始存放的字符串str1复制到将es:di开始存放的字符串str2中,str1将以0结尾,复制包括结束标记。调用时保证str2的空间大于str1。;参数:ds:si开始存放的字符串str1,es:di开始存放的字符串str2
;返回: 无

DATAS SEGMENT

     db'Happy day',0 ;源地址,0为结束符

str2 db 32 dup(1)  ;目的地址

DATAS ENDS

CODES SEGMENT

    ASSUME CS:CODES,DS:DATAS

START:

    MOV AX,DATAS

    MOV DS,AX

    mov si,0    ;源地址ds:si

    mov es,ax  

    mov ax,offset str2

    mov di,ax   ;目的地址es:di

    call strcpy

    MOV AH,4CH

    INT 21H

    

    strcpy proc

    mov cx,str2-DATAS  ;传送长度=str2标号偏移-DATAS段偏移

    cld   ;设置df=0,正向传送

    rep movsb  ;串传送

    ret

    strcpy endp

    

CODES ENDS

END START

4、附加题

有一个sc的长度为16的成绩数组,统计成绩为优秀(>=90)、良好(89~80)、中等(79~70)、及格(69~60)、不及格的人数(<60),分别放入numa、numb、numc、numd、nume中。编写程序完成以上功能。

DATAS SEGMENT

 sc db 90,91,50,49,77,88,41,55,33,86,48,59,69,89,56,87

 numa db 0

 numb db 0

 numc db 0

 numd db 0

 nume db 0

DATAS ENDS

CODES SEGMENT

    ASSUME CS:CODES,DS:DATAS

START:

    MOV AX,DATAS

    MOV DS,AX

    mov bx,0

    mov cx,16  ;数组长度16

    call grade

    

    MOV AH,4CH

    INT 21H

    

    grade proc

  s:mov al,[bx]

    inc bx  ;bx总指向下一个

    cmp al,90  ;al>=90则跳转a

    jae a

    cmp al,80  ;90>al>=80则跳转b

    jae b

    cmp al,70  ;80>al>=70则跳转c1

    jae c1

    cmp al,60  ;70>al>=60则跳转d

    jae d

    inc [nume]  ;60>al

 s2:loop s

    jmp s1  ;loop结束则程序结束

    

  a:inc [numa]

    jmp s2

  b:inc [numb]

    jmp s2

 c1:inc [numc]

    jmp s2

  d:inc [numd]

jmp s2

    

 s1:ret

    grade endp

    

CODES ENDS

END START

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

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

相关文章

亚马逊新店铺流量怎么提升?自养号测评新趋势

在竞争激烈的电商市场中&#xff0c;亚马逊新店铺如何在众多竞争者中脱颖而出&#xff0c;提升流量成为一大难题。对于新手卖家来说&#xff0c;掌握正确的流量提升策略至关重要。本文将为您揭秘亚马逊新店铺流量提升的方法&#xff0c;助您快速打开市场&#xff0c;实现业绩增…

FPGA自分频产生的时钟如何使用?

对于频率比较小的时钟&#xff0c;使用clocking wizard IP往往不能产生&#xff0c;此时就需要我们使用代码进行自分频&#xff0c;自分频产生的时钟首先应该经过BUFG处理&#xff0c;然后还需要进行时钟约束&#xff0c;处理之后才能使用。

JQuery基本介绍和使用方法

JQuery基本介绍和使用方法 W3C 标准给我们提供了⼀系列的函数, 让我们可以操作: ⽹⻚内容⽹⻚结构⽹⻚样式 但是原⽣的JavaScript提供的API操作DOM元素时, 代码⽐较繁琐, 冗⻓. 我们可以使⽤JQuery来操作⻚⾯对象. jQuery是⼀个快速、简洁且功能丰富的JavaScript框架, 于20…

Go语言中的值类型和引用类型特点

一、值类型 值类型的数据直接包含值&#xff0c;当它们被赋值给一个新的变量或者作为参数传递给函数时&#xff0c;实际上是创建了原值的一个副本。这意味着对新变量的修改不会影响原始变量的值。 Go中的值类型包括&#xff1a; 基础类型&#xff1a;int&#xff0c;float64…

15-spring整合mybatis方式一

spring整合mybatis 方式一【重要】 步骤: 1.导入相关jar包 junit mybatis mysql数据库 spring相关的 aop织入 mybatis-spring 【new】 junit junit 4.12 mysql mysql-connector-java 8.0.23 org.mybatis mybatis 3.5.2 org.springframework spring-webmvc 5…

豆包MarsCode:小C的类二进制拼图

问题描述 思路分析 1. 类二进制数字定义 从题目中我们可以知道&#xff0c;类二进制数字是仅由 0 和 1 组成的数字。比如&#xff1a;1, 10, 100, 101, 110 等等&#xff0c;这些数字都是合法的类二进制数字。换句话说&#xff0c;类二进制数字可以看作是 “二进制表示法” 对…

中国综合算力指数(2024年)报告汇总PDF洞察(附原数据表)

原文链接&#xff1a; https://tecdat.cn/?p39061 在全球算力因数字化技术发展而竞争加剧&#xff0c;我国积极推进算力发展并将综合算力作为数字经济核心驱动力的背景下&#xff0c;该报告对我国综合算力进行研究。 中国算力大会发布的《中国综合算力指数&#xff08;2024年…

Vue中设置报错页面和“Uncaught runtime errors”弹窗关闭

文章目录 前言操作步骤大纲1.使用Vue自带的报错捕获机制添加报错信息2.在接口报错部分添加相同机制3.把报错信息添加到Vuex中方便全局使用4.添加报错页面备用5.app页面添加if判断替换报错界面 效果备注&#xff1a;vue项目中Uncaught runtime errors:怎样关闭 前言 在开发Vue项…

单调栈详解

文章目录 单调栈详解一、引言二、单调栈的基本原理1、单调栈的定义2、单调栈的维护 三、单调栈的应用场景四、使用示例1、求解下一个更大元素2、计算柱状图中的最大矩形面积 五、总结 单调栈详解 一、引言 单调栈是一种特殊的栈结构&#xff0c;它在栈的基础上增加了单调性约束…

算法题之栈与队列:理论基础与常用操作接口

栈与队列 &#xff08;1&#xff09;理论基础 栈&#xff1a;先进后出的数据结构 队列&#xff1a;先进先出的数据结构 栈提供push 和 pop 等等接口&#xff0c;所有元素必须符合先进后出规则&#xff0c;所以栈不提供走访功能&#xff0c;也不提供迭代器(iterator)。 不像是…

snippets router pinia axios mock

文章目录 补充VS Code 代码片段注册自定义组件vue routerpinia删除vite创建项目时默认的文件axiosmock3.0.x版本的 viteMockServe 补充 为文章做补充&#xff1a;https://blog.csdn.net/yavlgloss/article/details/140063387 VS Code 代码片段 为当前项目创建 Snippets {&quo…

llama-2-7b权重文件转hf格式及模型使用

目录 1. obtain llama weights 2. convert llama weights files into hf format 3. use llama2 to generate text 1. obtain llama weights &#xff08;1&#xff09;登录huggingface官网&#xff0c;搜索llama-2-7b &#xff08;2&#xff09;填写申请表单&#xff0c;VP…

图形化数据报文转换映射工具

目录 概要整体架构流程技术名词解释技术细节小结 概要 在当今数字化时代&#xff0c;数据的处理和分析是企业、科研机构以及各类组织日常运营的核心环节。数据来源广泛&#xff0c;格式多样&#xff0c;常见的数据格式包括XML&#xff08;可扩展标记语言&#xff09;和JSON&a…

计算机视觉算法实战——无人机检测

✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连 ✨ ✨个人主页欢迎您的访问 ✨期待您的三连✨ ​ ​ 1. 引言✨✨ 随着无人机技术的快速发展&#xff0c;无人机在农业、物流、监控等领域的应用越来越广泛。然而&#xff0c;无人机的滥用也带…

我谈概率论与数理统计的知识体系

学习概率统计二十多年后&#xff0c;在廖老师的指导下&#xff0c;厘清了各章之间的关系。本来就是一条线两个分支&#xff0c;脉络很清晰。 分支一&#xff1a;从随机现象到样本空间到随机事件再到概率。 从随机事件到随机变量&#xff1a;为了进行定量的数学处理&#xff0…

docker ubuntu:20.04构建c++ grpc环境

由c grpc必须源码编译&#xff0c;ubuntu版本不同可能出现的问题也不同&#xff0c;这里分享下我的构建过程。 我是vscode结合docker去安装c虚拟环境&#xff0c;我不想污染本机环境。 vscode的插件Dev Containers Dockerfile如下(如果单纯是ubuntu环境构建&#xff0c;可忽略该…

使用KNN实现对鸢尾花数据集或者自定义数据集的的预测

创建自定义数据集&#xff1a; point1[[7.7,6.1],[3.1,5.9],[8.6,8.8],[9.5,7.3],[3.9,7.4],[5.0,5.3],[1.0,7.3]] point2[[0.2,2.2],[4.5,4.1],[0.5,1.1],[2.7,3.0],[4.7,0.2],[2.9,3.3],[7.3,7.9]] point3[[9.2,0.7],[9.2,2.1],[7.3,4.5],[8.9,2.9],[9.5,3.7],[7.7,3.7],[9.…

Go学习:常量

变量&#xff1a;程序运行期间&#xff0c;可以改变的量&#xff0c;变量声明需要使用 var 常量&#xff1a;程序运行期间&#xff0c;不可以改变的量&#xff0c;常量声明需要使用 const 目录 1. 常量不允许修改 2. 常量赋值不使用 : 3. 常量能够自动推导类型 1. 常量不允许…

钉钉群机器人设置——python版本

钉钉群机器人设置——python版本 应用场景钉钉界面操作程序开发效果展示 应用场景 由于工作需要&#xff0c;很多项目执行程序后出现报错信息无法第一时间收到&#xff0c;因此实时预警对于监控程序还是有必要。&#xff08;仅个人观点&#xff09; 参考文档及博客&#xff1a…

Effective Python系列(1.1):区别bytes和str

本篇文章是 Effective Python 这本书的第一章&#xff0c;本章的主要内容是什么样的代码风格才是比较符合 Python 语言。 在 Python 当中&#xff0c;bytes 和 str 是两种不同的数据结构。使用时&#xff0c;需要注意两者区别&#xff1a; bytes 包含的是由 8 位值所组成的序列…