课程名称:微处理器原理与应用
实验名称:CPUHomework3
实验时间:2022年10月16日
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
debug中P命令与T命令的区别
P和T都是执行,像 add ax, bx,不管用哪个,都是执行此语句
但如果是 call next, next是一个程序段,那么用P直接就把这段程序执行完,用T则进入内部一句一句执行(与C语言的调试一样,有的进入函数内部,有的执行完函数)
T(跟踪)命令:执行以 cs:ip 开始的一个或几个指令,并显示出执行每条指令后所有寄存器中的内容
P 执行循环、重复的字符串指令、软件中断或子例程
执行命令 G
G [=<地址>[,<断点>]]
等价于:
G
G=<地址>
G=<地址>,<断点>
功能:执行内存中的指令序列
1. 从 CS:IP 所指出开始执行
2. 从指定地址开始执行
3. 从指定地址开始执行,到断点自动停止
编写程序,详细注释并画程序流程图
代码如下:
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
流程图**(流程图格式使用默认)**如下:
具体代码测试结果如下:
通过注释重点学习并理解程序,活出程序流程图,在理解的基础上可自行修改
代码如下:
示例程序
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为进位或借位标识符,被运算结果所影响
学习和改进程序
不断改造,能力进步
示例: 求和 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开始的字符串输出到屏幕
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 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