【实验作业】微处理器原理与应用 CPUHomework3【子程序汇编实验 流程图 十六进制数转十进制数 键盘录入 屏幕显示 闰年判断 两位数求和 汇编小程序】

实验报告

课程名称:微处理器原理与应用

实验名称:CPUHomework3

实验时间:2022年10月16日

实验三 子程序汇编实验学习和提高

汇编语言中的 ASSUME 伪指令和标准的汇编程序

ASSUME伪指令,通知汇编程序(编译器)代码段,数据段,附加段以及堆栈段选择什么名字

没有 ASSUME 伪指令时,汇编程序假设不分段,并自动把段超越前缀用于所有所有寻址存储器数据的伪指令

ASSUME 语句只能用于完整的段定义, ASSUME 不是汇编指令,仅仅是写给编译软件的,是让编译器知道我的程序的各个段的名字,并不产生机器码

ASSUME 伪指令是指明变量与段寄存器的联系,如 ASSUME DS:DATAS, 告诉编译器以后所有在 DATAS 段中定义的变量寻址时,使用DS作为段地址,但是其不对程序作任何事(伪指令),我们必须自己对DS赋值

因此,要让机器知道实际的段地址,还需要 MOV AX,DATAS MOV DS,AX 告诉CPU数据段的地址

标准格式:
DETAS SEGMENT
	;
DATAS ENDS

STACKS SEGMENT
	;
STACKS ENDS

CODES SEGMENT
	ASSUME CS:CODES,DS:DATAS,SS:STACKS
START:
	MOV AX,DATAS
	MOV DS,AX	; 告诉CPU数据段的地址
	...
	; 此处输入代码段代码
	...
	MOV AH,4CH
	INT 21H
CODES ENDS
	END START

1. 复习 Debug -P 和 -G

debug中P命令与T命令的区别

  1. P和T都是执行,像 add ax, bx,不管用哪个,都是执行此语句

    但如果是 call next, next是一个程序段,那么用P直接就把这段程序执行完,用T则进入内部一句一句执行(与C语言的调试一样,有的进入函数内部,有的执行完函数)

  2. T(跟踪)命令:执行以 cs:ip 开始的一个或几个指令,并显示出执行每条指令后所有寄存器中的内容

P 执行循环、重复的字符串指令、软件中断或子例程

执行命令 G

G [=<地址>[,<断点>]]
等价于:
G
G=<地址>
G=<地址>,<断点>
功能:执行内存中的指令序列
1. 从 CS:IP 所指出开始执行
2. 从指定地址开始执行
3. 从指定地址开始执行,到断点自动停止

2. 将键盘上输入的十六进制数转换成十进制数,并在屏幕上显示

编写程序,详细注释并画程序流程图

代码如下:

data segment	; 定义数据段
	infon db 0dh,0ah,'Please input a hexadecimal number: $'	; 声明空间存储输入提示信息,其中0d回车,0a换行
	wrong db 0dh,0ah,'Please input a valid hexadecimal number: $ is wrong'	; 报错
data ends

stack segment stack
	dw 10 dup(?)
stack ends	; 定义一个栈,有10个字的空间

code segment
	assume cs:code,ds:data,ss:stack
start:
	mov ax,data
	mov ds,ax	; 将数据段的地址交给ds
	
	lea dx,infon	; 使用lea将infon中的内容交给dx,从而在屏幕上显示提示信息
	mov ah,09h	; 将09h交给ah
	int 21h	; 输出提示信息
	
	mov bx,0

input:
	mov ah,01h
	int 21h	; 从键盘上输入一个字符,将之对应的ASCII码交给al,并在屏幕上显示
	add dx,1
	cmp al,0dh
	je z	; 如果相等,则跳转到zz

judge:
	cmp al,'f'	; 比较输入字符与'f'的ASCII码大小
	ja err	; 无符号大于跳转到err
	cmp al,'a'
	jnb branch1	; 无符号不小于跳转到branch1
	
	cmp al,'F'
	ja err	; 无符号大于跳转到err
	cmp al,'a'
	jnb branch2	; 无符号不小于跳转到branch2
	
	cmp al,'9'
	ja err
	cmp al,'0'
	jnb branch3	; 同理
	
	jmp err

err:	; 报错
	lea dx,wrong
	mov ah,09h
	int 21h	; 输出提示语句
	jmp input	; 跳转,重新输入
	
branch1:
	sub al,57h	; a~f, al-57h
	jmp tran
	
branch2:
	sub al,37h	; A~F, al-37h
	jmp tran
	
branch3:
	sub al,30h	; 0~9, al-30h
	jmp tran

tran:
	add dx,1
	mov ah,0h
	je input
	mov cx,04h	; 循环次数为4
shift:	rol bx,1	; bx左移4位
	loop shift
	add bx,ax
	jmp input
	
z:
	mov ax,bx
	mov bx,10
	mov cx,0
	
cir:
	mov dx,0
	add cx,1
	div bx
	push dx
	cmp ax,0
	jne cir
	
fin:
	pop ax	; 余数出栈
	mov dl,al	; al的数据交给dl准备输出
	add dl,30h	; 余数在1~9之间,al + 30
	mov ah,2
	int 21h	; 输出十进制数
	loop fin	; 根据cx的值进行循环输出
	jmp stop

stop:
	mov ah,4ch
	int 21h
	code ends
end start

ROL:循环左移指令
ROL BX, 1 ; 将BX的二进制数全部左移1位,原最高位移入最低位,且复制至进位标志CF
例如,BX原值 =1100 1111 0000 0000 , CF=0
ROL BX, 1 结果: BX=1001 1110 0000 0001 , CF=1

流程图**(流程图格式使用默认)**如下:

在这里插入图片描述

具体代码测试结果如下:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

3. 较为复杂的汇编实例学习:判断该年是否为闰年

通过注释重点学习并理解程序,活出程序流程图,在理解的基础上可自行修改

代码如下:

示例程序
data segment	; 定义数据段
	infon db  0dh,0ah,'Please input a year: $'	; 声明空间存储输入提示信息,其中0d回车,0a换行
	Y db  0dh,0ah,'This is a leap year! $'	; 声明空间存储的是闰年提示信息,同上另起一行输出
	N db  0dh,0ah,'This is not a leap year! $'	; 声明空间存储不是闰年提示信息,同上另起一行输出
	w dw 0	; 声明空间存储输入年份解析后生成的年份数字
	buf db 8
		db ?
		db 8 dup(?)	; 声明空间作为缓冲区,总共10个字节,第一个表示准备接收的字符数,即8
		; 第二个表示实际接受的字符数,初始为空(?)
		; 后面8个字节作为缓冲接收字符,后两行知识做初始化工作

data ends

stack segment stack
	db 200 dup(0)
stack ends	; 定义一个栈,200字节

code segment
		assume ds:data,ss:stack,cs:code
	start: mov ax,data
		   mov ds,ax	; 指定数据段
	
	lea dx,infon	; 在屏幕上显示提示信息
	mov ah,9
	int 21h	; 将infon开始的字符串输出到屏幕
	
	lea dx,buf	; 从键盘输入年份字符串
	mov ah,10
	int 21h
	
	mov cl,[buf+1]	; 获取实际输入长度
mov ch,0	; 保证cx的值为[buf+1]对应字节的值
	lea di,buf+2	; 获取字符串首地址
	call datacate	; 调用子程序,将输入字符串转化为年份数字
	call ifyears	; 调用子程序,判断是否是闰年
	jc a1	; 如果进位标记C为1则跳转到a1
	
	lea dx,n	; 否则输出不是闰年的信息
	mov ah,9
	int 21h
	jmp exit
a1:	lea dx,y	; 输出是闰年的信息
	mov ah,9
	int 21h
exit: mov ah,4ch	; 程序结束
	int 21h
		
datacate proc near	; 指明该子程序在主程序段内
	push cx	; 备份cx
	dec cx	; cx自减1,保证下面的循环使si指向最后一个字符(buf中回车符前面的一个)
	lea si,buf + 2	; 将buf中第一个字符(及buf中第三个字节数据)的地址赋给si
tt1: inc si	; 循环,使得si指向最后一个字符(即buf中回车符前面的一个)
	loop tt1
	pop cx	; 回复cx
	
	mov dh,30h	; 辅助数据,用来将数字字符对应的ASCII码转换为其代表的数字本身
	mov bl,10	; 辅助数据,用来在每进一位时使得ax乘以10
	mov ax,1	; ax用来装对应位的权值
l1: push ax	; 备份ax
push bx ; 备份bx
push dx ; 备份dx,下面的dx将接收乘法运算结果的高位(实际上本例中没有任何作用,因为乘法结果不会超过ax表示的范围)
; 之所以需要是因为有时乘数(某些权值)需要用两个字节来表示

	sub byte ptr  [si],dh	; 将的那个字符转换为对应的数字
	mov bl, byte ptr [si]	; 获取该位数字
mov bh,0	;因为 1. 我们要用两个个字节装对应位的数字 2. 该数字不会超过一个字节表示的范围
	mul bx	; 将该位数字乘以相应的权值,结果存储在ax中,我们预定年份最大值不超过两个字节表示的范围
	add [w],ax	; 加到结果上(易知当所有位都加完时,即是我们想要的年份数字)
	pop dx	; 恢复dx
	pop bx	; 恢复bx
		pop ax	; 恢复ax
		mul bl	; 权值乘以10
		dec si	; si指向更高一位数字
		loop l1
		ret	; 子程序返回
datacate endp

ifyears proc near	;指明该子程序段在主程序段内,该子程序用于检测是否是闰年,接收年份数据,改变c标记位表示不同结果
	push bx	; 备份bx
	push cx	; 备份cx,下面cx用于存储原始年份数据
	push dx	; 备份dx,下面dx用于存储除法余数
	mov ax,[w]	; 获取年份数据
	mov cx,ax	; 将年份数据备份到cx,因为后面做除法时ax值将会改变
	mov dx,0	; 因为被除数要为32字节,高位在dx,本程序中为0
mov bx,100	; 这三行半段是否能被100整除
	div bx
	cmp dx,0
	jnz lab1
	mov ax,cx
mov bx,400
	div bx
	cmp dx,0
	jz lab2	;若能表示是闰年,跳转到lab2
	clc	; 否则不是闰年,将c标记位清零,并跳转到lab3
	lab1:mov ax,cx	; 不能被100整除时跳转到此处,进一步判断能否被4整除
		mov dx,0
		mov bx,4
		div bx
		cmp dx,0
		jz lab2	; 若不能被100整除但能被4整除时闰年,跳转到lab2
		clc	; 若不能被100整除也不能被4整除不是闰年,将c标志位置零,并跳转到lab3
			jmp lab3
		lab2:stc	; 若是闰年跳转到此处将c标志位置1
		lab3: pop dx	; 相应寄存器恢复
		pop cx
		pop bx
		ret	; 子程序返回
	ifyears endp
code ends
	end start

流程图如下:

在这里插入图片描述

请添加图片描述

请添加图片描述

复习一下:

加载有效地址(load effective address)指令就是lea,他的指令形式就是从内存读取数据到寄存器,但是实际上他没有引用内存,而是将有效地址写入到目的的操作数,就像是C语言地址操作符&一样的功能,可以获取数据的地址

jc,如果CF = 1,则跳转至指定位置

jnc,如果CF = 0,则跳转

CF为进位或借位标识符,被运算结果所影响

4. 汇编实例学习和改进:两位数加法

学习和改进程序

不断改造,能力进步

示例: 求和 3 + 5
datas segment
	five db	5	; 定义five为值为5的字节变量
datas ends

stacks segment
	db  128 dup(?)	; 定义一个128字节的栈空间
stacks ends

codes segment
	assume  cs:codes,ds:datas,ss:stacks
start:	; 主程序
	mov ax,datas	; 段地址交给段寄存器
	mov ds,ax
	mov al,five	; 将5交给al
	
	add al,3	; al与3相加并将结果交给al
	add al,30h	; al与30h相加,得到ASCII码
	
	mov dl,al	; 将ASCII码交给dl准备输出
	mov ah,2
	int 21h	; 输出dl
	
	mov ah,4ch
	int 21h	; 返回DOS
codes ends	; 代码段结束 
	end start	; 程序结束

在这里插入图片描述

上面的程序是在程序内部定义的数据,以下改进可以使之从键盘输入

start:
	mov ax,datas
	mov ds,ax
	mov bl,five
	
	mov ah,1
	int 21h
	
	add al,bl
	
	mov dl,al
	mov ah,2
	int 21h

显然这样不够完善,能否实现输入两个变量,然后相加,我们可以使用以下代码

data segment
	x db 0
	y db 0
	info db 0dh,0ah,'Please input a number: $'
	info2 db 0dh,0ah,'Please input another number: $'
	adds db '+$'
	res db '=$'
data ends

stack segment
	db 128 dup(?)
stack ends

code segment
	assume cs:code,ds:data,ss:stack

start:
	mov ax,data	; 将data的段地址交给ds
	mov ds,ax
	
	lea dx,info	; 在屏幕上显示提示信息
	mov ah,9
	int 21h	; 将infon开始的字符串输出到屏幕
	
	mov ah,1
	int 21h	; 从键盘上输入字符
	sub al,30h	; al的值-30h,转换为对应的数字
	mov x,al
	lea dx,adds
	mov ah,9
	int 21h	; 输出
	
	lea dx,info2	; 在屏幕上显示提示信息
	mov ah,9
	int 21h	; 将infon2开始的字符串输出到屏幕
	
	mov ah,1
	int 21h	; 从键盘上输入字符
	sub al,30h	; al的值-30h,转换为对应的数字
	mov y,al
	lea dx,res
	
	mov ah,9
	int 21h
	mov al,x
	add al,y
	add ax,30h	; 将ax的值+30h转换为对应的ASCII码
	
	mov dl,al
	mov ah,2
	int 21h
	
	mov ah,4ch
	int 21h
code ends
end start

运行结果如下:

在这里插入图片描述

但显然不能输入和输出两位数:

在这里插入图片描述

接下来编写两位数求和的程序代码

data segment
	info1 db 0dh,0ah,'Enter the first number: $'
	info2 db 0dh,0ah,'Enter the second number: $'
	info3 db 0dh,0ah,'Sum is: $'
	
	buf1 db 8
		db ?
		db 8 dup(?)	; 声明空间作为缓冲区,总共10个字节,第一个表示准备接收的字符数,即8
		; 第二个表示实际接受的字符数,初始为空(?)
		; 后面8个字节作为缓冲接收字符,后两行知识做初始化工作
		
	buf2 db 8
		db ?
		db 8 dup(?)
	data ends

stack segment stack
	db  128 dup(?)	; 定义一个128字节的栈空间
stack ends

code segment
	assume cs:code,ds:data,ss:stack

start:
	mov ax,data
	mov ds,ax
	
	lea dx,info1
	mov ah,9
	int 21h
	
	lea dx,buf1
	mov ah,0ah
	int 21h	; 输入一个两位数
	mov bl,[buf1 + 2]	; 将十位交给bl
	sub bl,'0'	; 转ASCII码为数字
	mov bh,[buf1 + 3]	; 将个位交给bh
	sub bh,'0'	; 同理转为数字
	
	lea dx,info2
	mov ah,9
	int 21h
	
	lea dx,buf2
	mov ah,0ah
	int 21h ; 输入第二个两位数
	
	lea dx,info3	; 输出结果
	mov ah,9
	int 21h
	
	mov cl,[buf2 + 2]	; 将十位交给cl
	sub cl,'0'
	mov ch,[buf2 + 3]	; 将个位交给ch
	sub ch,'0'
	
	add bl,cl	; 十位相加
	add bh,ch	; 个位相加
	
	cmp bh,10	; 考虑进位
	jge carry1	; 大于等于则进位
	jmp carry2
	
carry1:
	sub bh,10	; 个位减10
	add bl,1	; 十位进1
	jmp carry2	; 判断十位
	
carry2:
	cmp bl,10
	jge carry3	; 大于等于则进位
	jmp fin
	
carry3:
	sub bl,10	; 十位减10
	mov dl,31h
	mov ah,02h
	int 21h
	jmp fin

fin:
	mov dl,bl
	add dl,30h
	mov ah,02h
	int 21h	; 将十位的值转化为ASCII码并交给dl并输出
	
	mov dl,bh
	add dl,30h
	mov ah,02h
	int 21h	; 将个位的值转化为ASCII码并交给dl并输出
	
	mov ah,4ch
	int 21h	; 返回DOS
code ends
end start

最终流程图如下:

在这里插入图片描述

运行结果如下:

在这里插入图片描述

进位也没有问题

在这里插入图片描述

【基础学习】

栈的定义

db 字节 dw 字 DUP(duplicate) 重复

DB (define byte) : 定义一个字节类型的变量,其后的每个操作数均占用1个字节

DW (define word): 定义一个字类型的变量,其后的每个操作数均占用1个字(2个字节)

DD (define doubleword): 定义一个双字类型的变量,其后的每个操作数均占用2个字(4个字节)

DQ (define quadword): 定义一个四字类型的变量,其后的每个操作数

DT (define ten bytes): 定义一个十字节类型的变量,其后的每个操作数占用5个字(10个字节)

比如
stack segment stack
	db 200 dup(0)
stack ends		; 定义一个栈,200字节
STACKS SEGMENT STACK	; 栈段
	DW 128 DUP(?)	; 注意这里只有128个字
STACKS ENDS

qword全称是Quad Word

2个字节就是1个Word(1个字,16位),q就是英文quad-这个词根(意思是4)的首字母,所以它自然是word(2字节)的四倍,也就是8字节

此外,它还是 Pascal 和 nasm 语言中的关键字

显示提示信息方法

lea dx,infon	; 在屏幕上显示提示信息
mov ah,9
int 21h		; 将infon开始的字符串输出到屏幕

键盘输入方式

从键盘输入一个字符串到缓冲区(AH=0AH)

  • 功能:从键盘输入一串ASCII码字符到缓冲区,输入结束为缓冲区的个数或者回车字符
  • 入口参数: DX=缓冲区首偏移地址; DS=缓冲区段地址
  • 调用方法:
MOV  AX,缓冲区的首址的段地址
MOV  DS,AX
MOV  DX, 缓冲区的首址的偏移地址
MOV  AH, 0AH
INT  21H
  • 执行完上面的调用,将从键盘接受字符串送到内存的输入缓冲区(由DS:DX指定缓冲区),需预先定义一个缓冲区

  • 缓冲区的第一个字节指定容纳的最大字符个数,由用户给出

  • 第二个字节存放实际的最大字符个数,由系统最后添入

  • 从第三个字节开始存放从键盘接受的字符,直到ENTER键结束

e.g.

DATA SEGMENT
BUF DB 20	; 存放最大字符个数20个
    DB ?	; 存放实际输入字符个数
    DB 20 DUP(?)	; 存放输入字符
DATA ENDS

mul 乘法指令

理解 mul bx 和 mul bl

MUL 汇编语言无符号数乘法指令

MUL  SRC  执行的操作:
字节操作数: (AX)<--(AL)*(SRC)
字操作数:   (DX,AX)<--(AX)*(SRC)

编写程序从理解范例程序开始,在masm for windows 软件中实现效果,并通过注释进一步理解汇编语言的写法规范,以及汇编中子程序的写法(call 和 ret指令,详见王爽第十章),学习 jmp 跳转语句的使用,画出程序实现的流程图

实验心得

这次的实验比以往的都要综合,因此也更加复杂,但通过流程图的绘制以及不断地报错调试,最终可以实现完整的程序功能

这次的汇编程序编写有当初学习C语言的感觉,感觉基本逻辑和框架差不多,但是汇编要更偏向于底层,我们通常在与寄存器(静态的数据),各种指令(动态的语句),从某种程度上让我对数据结构与算法有了更加具体的感受,也加深了对计算机以及微处理器的了解

子程序调用也很像高级语言中的函数调用,跳转的实现使得语句(代码块)可以得到封装,从而提升了程序的灵活性

【程序欣赏】

My heart beats with yours

在 masm for windows 中运行

Data segment 
full db 0 
buff1 db ' Welcome you to run this programme!' 
 db ' ' 
 db ' *****Please press any key*****$' 
buff2 db ' My heart beats with yours!' 
 db ' ***** Please q to quit *****$' 
Data ends 
code segment 
 assume cs: code , ds: Data 
start: 
 push ds 
 sub ax,ax 
 push ax 
 mov ax, Data 
 mov ds, ax 
 mov ah, 0 
 mov al, 4 
 int 10h 
 mov ah,0bh 
 mov bh, 0 
 mov bl, 1 
 int 10h 
 mov ah,0bh 
 mov bh, 1 
 mov bl, 2 
 int 10h 
 mov dx,offset buff1 ;显示提示信息 
 mov ah, 9 
 int 21h 
 mov ah, 8 
 int 21h 
 call clear ;cls 
sss: 
 call text ;display the text 
 mov di, 2 
 mov al,1 ;draw the big box 
 mov cx, 70 
 mov dx, 20 
 mov bx, 160 
 Call box 
 mov cx, 71 
 mov dx, 21 
 mov bx, 158 
again: 
 mov al, 1 
 mov di, 0 
 Call box 
 Call delay 
 mov al, 0 
 mov di, 0 
 Call box 
 inc cx 
 inc dx 
 sub bx,2 
 cmp cx, 94 
 jnz again 
 mov di,0 ;draw the 2nd box 
 mov cx, 95 
 mov dx, 45 
 mov al, 1 
 mov bx, 110 
 Call box 
 mov cx, 96 
 mov dx, 46 
 mov bx, 108 
again_00: 
 mov al, 1 
 mov di, 0 
 Call box 
 Call delay 
 Call delay 
 mov al, 0 
 mov di, 0 
 Call box 
 inc cx 
 inc dx 
 sub bx,2 
 cmp cx, 114 
 jnz again_00 
 mov cx,115 ;draw the 3rd box 
 mov dx, 65 
 mov al, 1 
 mov bx, 70 
 Call box 
 mov cx, 116 
 mov dx, 66 
 mov bx, 68 
again_01: 
 mov al, 1 
 mov di, 0 
 Call box 
 Call delay 
 Call delay 
 mov al, 0 
 mov di, 0 
 Call box 
 inc cx 
 inc dx 
 sub bx,2 
 cmp cx, 129 
 jnz again_01 
 mov di, 2 
 mov al,1 ;draw the small box 
 mov cx, 130 
 mov dx, 80 
 mov bx, 40 
 Call box 
 mov di, 2 
 mov al,3 ;对角线 
 mov si, 0 
 mov cx, 71 
 mov dx, 21 
 mov bx, 59 
 Call xie_line 
 mov cx, 171 
 mov dx, 121 
 mov bx, 59 
 Call xie_line 
 mov si, 1 
 mov cx, 71 
 mov dx, 179 
 mov bx, 59 
 Call xie_line 
 mov cx, 171 
 mov dx, 79 
 mov bx, 59 
 Call xie_line 
 mov cx,150 ;十字线 
 mov dx, 20 
 mov si, 0 
 mov bx, 60 
 Call draw_line 
 mov cx, 150 
 mov dx, 120 
 mov bx, 60 
 Call draw_line 
 mov cx, 70 
 mov dx, 100 
 mov si, 1 
 mov bx, 60 
 Call draw_line 
 mov cx, 170 
 mov dx, 100 
 mov bx, 60 
 Call draw_line 
 mov si, 1 
 mov cx, 70 
 mov dx, 60 
 mov bx, 60 
 Call mid_line 
 mov cx, 170 
 mov dx, 110 
 mov bx, 60 
 Call mid_line 
 mov si, 2 
 mov cx, 110 
 mov dx, 20 
 mov bx, 30 
 Call mid_line 
 mov cx, 160 
 mov dx, 120 
 mov bx, 30 
 Call mid_line 
 mov si, 3 
 mov cx, 70 
 mov dx, 140 
 mov bx, 60 
 Call mid_line 
 mov cx, 170 
 mov dx, 90 
 mov bx, 60 
 Call mid_line 
 mov si, 4 
 mov cx, 110 
 mov dx, 180 
 mov bx, 30 
 Call mid_line 
 mov cx, 160 
 mov dx, 80 
 mov bx, 30 
Call mid_line 
 mov di, 0 
 mov al,1 ;draw the big box again 
 mov cx, 70 
 mov dx, 20 
 mov bx, 160 
Call box 
 mov di, 0 
 mov al,1 ;draw the small box again 
 mov cx, 130 
 mov dx, 80 
 mov bx, 40 
Call box 
 mov di, 0 
 mov cx, 95 
 mov dx, 45 
 mov al, 1 
 mov bx, 110 
Call box 
 mov cx, 115 
 mov dx, 65 
 mov al, 1 
 mov bx, 70 
Call box 
 mov di,1 ;fill 
Call fill 
Call fill_2 
Call fill_3 
 mov cx,149 ;bold 
 mov dx, 120 
 mov al, 2 
 mov bx, 60 
 mov si, 0 
Call draw_line 
 mov cx, 151 
 mov dx, 120 
 mov al, 2 
 mov bx, 60 
 mov si, 0 
Call draw_line 
heart_: ;draw the heart 
Call cls_box 
Call heart 
 mov ah, 8 
 int 21h 
 cmp al,'q' 
 jz ok 
 cmp al,20h 
 jz heart_ 
Call Clear 
 jmp sss 
ok: 
ret 
fill proc near ;the procedure of fill 
 mov full, 0 
 mov al, 5 
 mov cx, 160 
 mov dx, 121 
 mov si, 0 
 mov bx, 60 
fill_Y: 
 push cx 
 push dx 
 push bx 
Call draw_line 
 pop bx 
 pop dx 
 pop cx 
 sub bx,2 
 inc cx 
 Add dx, 2 
 inc full 
 cmp full, 30 
 jne fill_Y 
 ret 
fill endp 
fill_2 proc near 
 mov full, 0 
 mov al, 5 
 mov cx, 140 
 mov dx, 121 
 mov si, 0 
 mov bx, 60 
fill_Y1: 
 push cx 
 push dx 
 push bx 
Call draw_line 
 pop bx 
 pop dx 
 pop cx 
 sub bx,2 
 dec cx 
 Add dx, 2 
 inc full 
 cmp full, 30 
 jne fill_Y1 
ret 
fill_2 endp 
fill_3 proc near 
 mov al, 1 
 mov full, 0 
 mov si, 0 
 mov cx, 140 
 mov dx, 121 
 mov bx, 60 
re_fill: 
 push bx 
 push cx 
 push dx 
Call draw_line 
 pop dx 
 pop cx 
 pop bx 
 inc cx 
 inc full 
 cmp full, 9 
 jne re_fill 
 mov full, 0 
 mov cx, 159 
 mov dx, 121 
 mov bx, 60 
re_fill2: 
 push bx 
 push cx 
 push dx 
Call draw_line 
 pop dx 
 pop cx 
 pop bx 
 dec cx 
 inc full 
 cmp full, 9 
 jne re_fill2 
ret 
fill_3 endp 
draw_Line proc near ;the procedure of draw a line 
 push bx 
 cmp si, 0 
 jz V_line1 
 Add bx, cx 
H_line: 
 mov ah,0ch 
 int 10h 
 cmp di, 0 
 jz aa0 
 cmp di, 1 
 jz aa1 
Call delay 
aa1: 
Call delay 
aa0: 
 inc cx 
 cmp cx, bx 
 jne H_line 
 jmp exit_line 
V_line1: 
 Add bx, dx 
V_line: 
 mov ah,0ch 
 cmp di, 0 
 jz bb0 
 cmp di, 1 
 jz bb1 
Call delay 
bb1: 
Call delay 
bb0: 
 int 10h 
 inc dx 
 cmp dx, bx 
 jne V_line 
exit_line: 
 
 pop bx 
ret 
draw_line endp 
xie_line proc near ;the procedure of draw a xie_line 
 Add bx, cx 
 cmp si, 1 
 jz xieline_1 
xieline_0: 
 
 mov ah,0ch 
 int 10h 
 inc dx 
 inc cx 
 cmp cx, bx 
 jne xieline_0 
 jmp exit_xie 
xieline_1: 
 mov ah,0ch 
 int 10h 
 dec dx 
 inc cx 
 cmp cx, bx 
 jne xieline_1 
exit_xie: 
ret 
xie_line endp 
Mid_line proc near ;draw a xie_line 
 Add bx, cx 
 cmp si, 2 
 jz midline_2 
 cmp si, 3 
 jz midline_3 
 cmp si, 4 
 jz midline_4 
midline_1: 
 
 mov ah,0ch 
 int 10h 
 inc dx 
 Add cx, 2 
 cmp cx, bx 
 jne midline_1 
 jmp exit_lines 
midline_2: 
 mov ah,0ch 
 int 10h 
 Add dx, 2 
 inc cx 
 cmp cx, bx 
 jne midline_2 
 jmp exit_lines 
midline_3: 
 mov ah,0ch 
 int 10h 
 dec dx 
 Add cx, 2 
 cmp cx, bx 
 jne midline_3 
 jmp exit_lines 
midline_4: 
 mov ah,0ch 
 int 10h 
 sub dx,2 
 inc cx 
 cmp cx, bx 
 jne midline_4 
exit_lines: 
ret 
mid_line endp 
box proc near ;draw a box 
 push cx 
 push dx 
 push cx 
 push dx 
 push cx 
 push dx 
 push cx 
 push dx 
 mov si, 1 
 call draw_line ;top 
 pop dx 
 pop cx 
 Add cx, bx 
 mov si, 0 
 call draw_line ;right 
 pop dx 
 pop cx 
 mov si, 0 
 call draw_line ;left 
 pop dx 
 pop cx 
 mov si, 1 
 Add dx, bx 
 call draw_line ;bottom 
 pop dx 
 pop cx 
 ret 
 box endp 
space proc near ;display a space 
 mov ah, 2 
 mov dl,' ' 
 int 21h 
 ret 
 Space endp 
 
 return proc near ;回车 
 mov ah, 2 
 mov dl,0ah 
 int 21h 
 mov dl,0dh 
 int 21h 
 ret 
 return endp 
 
 text proc near ;显示文本信息 
 mov bh, 0 
 mov dh, 0 
 mov dl, 0 
 mov ah, 2 
 int 10h 
 mov dx,offset buff2 
 mov ah, 9 
 int 21h 
 Text endp 
 
 heart proc near 
 mov cx,136 ;draw_heart 
 mov dx, 93 
 mov si, 0 
 mov bx, 5 
 mov al, 2 
 Call draw_line 
 mov cx,137 ;draw_heart 
 mov dx, 91 
 mov si, 0 
 mov bx, 9 
 Call draw_line 
 mov cx,138 ;draw_heart 
 mov dx, 90 
 mov si, 0 
 mov bx, 12 
 Call draw_line 
 mov cx,139 ;draw_heart 
 mov dx, 89 
 mov si, 0 
 mov bx, 14 
 Call draw_line 
 mov cx,140 ;draw_heart 
 mov dx, 88 
 mov si, 0 
 mov bx, 16 
 Call draw_line 
 mov cx,141 ;draw_heart 
 mov dx, 88 
 mov si, 0 
 mov bx, 17 
 Call draw_line 
 mov cx,142 ;draw_heart 
 mov dx, 87 
 mov si, 0 
 mov bx, 19 
 Call draw_line 
 mov cx,143 ;draw_heart 
 mov dx, 87 
 mov si, 0 
 mov bx, 20 
 Call draw_line 
 mov cx,144 ;draw_heart 
 mov dx, 87 
 mov si, 0 
 mov bx, 21 
 Call draw_line 
 mov cx,145 ;draw_heart 
 mov dx, 88 
 mov si, 0 
 mov bx, 21 
 Call draw_line 
 mov cx,146 ;draw_heart 
 mov dx, 88 
 mov si, 0 
 mov bx, 22 
 Call draw_line 
 mov cx,147 ;draw_heart 
 mov dx, 89 
 mov si, 0 
 mov bx, 22 
 Call draw_line 
 mov cx,148 ;draw_heart 
 mov dx, 90 
 mov si, 0 
 mov bx, 22 
 Call draw_line 
 mov cx,149 ;draw_heart 
 mov dx, 91 
 mov si, 0 
 mov bx, 22 
 Call draw_line 
 mov cx,150 ;1draw_heart 
 mov dx, 91 
 mov si, 0 
 mov bx, 22 
 Call draw_line 
 mov cx,151 ;draw_heart 
 mov dx, 90 
 mov si, 0 
 mov bx, 22 
 Call draw_line 
 mov cx,152 ;draw_heart 
 mov dx, 89 
 mov si, 0 
 mov bx, 22 
 Call draw_line 
 mov cx,153 ;draw_heart 
 mov dx, 88 
 mov si, 0 
 mov bx, 22 
 Call draw_line 
 mov cx,154 ;draw_heart 
 mov dx, 88 
 mov si, 0 
 mov bx, 21 
 Call draw_line 
 mov cx,155 ;draw_heart 
 mov dx, 87 
 mov si, 0 
 mov bx, 21 
 Call draw_line 
 mov cx,156 ;draw_heart 
 mov dx, 87 
 mov si, 0 
 mov bx, 20 
 Call draw_line 
 mov cx,157 ;draw_heart 
 mov dx, 87 
 mov si, 0 
 mov bx, 19 
 Call draw_line 
 mov cx,158 ;draw_heart 
 mov dx, 88 
 mov si, 0 
 mov bx, 17 
 Call draw_line 
 mov cx,159 ;draw_heart 
 mov dx, 88 
 mov si, 0 
 mov bx, 16 
 Call draw_line 
 mov cx,160 ;draw_heart 
 mov dx, 89 
 mov si, 0 
 mov bx, 14 
 Call draw_line 
 mov cx,161 ;draw_heart 
 mov dx, 90 
 mov si, 0 
 mov bx, 12 
 Call draw_line 
 mov cx,162 ;draw_heart 
 mov dx, 91 
 mov si, 0 
 mov bx, 9 
 Call draw_line 
 mov cx,163 ;draw_heart 
 mov dx, 93 
 mov si, 0 
 mov bx, 5 
 Call draw_line 
 ret 
 heart endp 
 
 delay proc near ;the procedure of delay 
 push cx 
 push dx 
 mov dx, 25 
dl2: 
 
 mov cx, 2801 
dl3: 
 
 loop dl3 
 dec dx 
 jnz dl2 
 pop dx 
 pop cx 
 ret 
 delay endp 
 
 clear proc near ;clear 
 mov al, 0 
 mov bx, 0 
 mov cx, 0 
 mov dx, 0 
line: 
 
 mov ah,0ch 
 int 10h 
 inc cx 
 cmp cx, 320 
 jne line 
 mov cx, 0 
 inc dx 
 cmp dx, 200 
 jne line 
 ret 
 Clear endp 
 
 cls_box proc near 
 mov al, 0 
 mov bx, 0 
 mov cx, 131 
 mov dx, 81 
s_line: 
 
 mov ah,0ch 
 int 10h 
 inc cx 
 cmp cx, 170 
 jne s_line 
 mov cx, 131 
 inc dx 
 cmp dx, 120 
 jne s_line 
 ret 
cls_box endp 
code ends 
 end start

结果如下:请添加图片描述

  • 10
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Zanebla

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值