一、实验目的
1) 利用本学期所学汇编知识完成一次综合设计。
2) 熟悉各种输入、输出方法的调用方法。
二、实验内容
设计一个打字练习软件,具体要求如下:
1)利用BIOS的屏幕窗口功能制作一个用户菜单,菜单包括:① 欢迎用语,提示按“ESC”键退出练习;② 开始练习,给出练习句子;③ 显示成绩和时间; ④ 退出用语
2)每次打字之前,屏幕上先显示出一个句子,然后打字员按照例句,将句中字符通过键盘输入。这个过程反复进行。利用BIOS 16H键盘功能调用来判断输入是否正确,不正确给出标示;
3)利用DOS系统时间调用计时,屏幕上以min:sec:msec的格式显示出练习时间
4)练习句子可用文件存储或定义在数据段中,定义10行,每行10个字符,区分大小写,分数根据准确率给出;允许中途退出,退出时给出提示语和选择,确定退出不给分和计时。
三、实验设备
PC机一台
四、实验步骤
1) 画出程序的主流程图和子程序流程图。
2) 输入源程序。
3) 汇编、连接程序,执行程序,检查结果。
4) 程序的执行可用DEBUG的G命令,也可用T命令单步跟踪执行。
五、实验报告的要求
1) 列出源程序。
2) 总结输入输出程序及菜单的编写方法。
3) 总结常用系统调用的功能及调用方法。
; multi-segment executable file template.
data segment
; add your data here!
;背景
bg db 1,10,22,61,2,11,21,60 ;前4个是边框,后四个是内容
center db 11,35 ;中心点偏左上一格的坐标
welcome1 db "*Welcome!"
lwelcome1 equ $-welcome1 ;长度
welcome2 db "*Input number to choose:"
lwelcome2 equ $-welcome2 ;长度
enter db 0dh,0ah,'$'
option1 db " #1.Start game"
loption1 equ $-option1 ;长度
option2 db " #2.Check the highest record"
loption2 equ $-option2 ;长度
option3 db " #Press 'ESC' Exit Game"
loption3 equ $-option3 ;长度
gameHint db "*Print the same string as follow!"
lgameHint equ $-gameHint
scoreHint db "Your score is:" ;分数的提示
lscoreHint equ $-scoreHint
hscoreHint db "Your highest score is:" ;最高分提示
lhscoreHint equ $-hscoreHint
gameTimeHint db "Used Time:" ;时间提示
lgameTimeHint equ $-gameTimeHint
gameOver db "Game Over,press any key to exit" ;游戏结束提示
lgameOver equ $-gameOver
anyKeyExit db "Press any key to exit" ;按任意键退出提示
lanyKeyExit equ $-anyKeyExit
opErrorHint db "Input error!" ;输入错误
lopErrorHint equ $-opErrorHint
exitHint db "Do you want to exit",63 ;退出提示,63是问号
lexitHint equ $-exitHint
exitOption1 db "#1.yes"
lexitOption1 equ $-exitOption1
exitOption2 db "#2.no"
lexitOption2 equ $-exitOption2
;操作号
op1 equ '1'
op2 equ '2' ;操作号
op3 equ 27 ;esc键
;时间
min db 0
second db 0
perSecond db 0
;游戏的串(顺序)
lstr equ 10
str1 db "Peacefully"
str2 db "Enthraller"
str3 db "StayStrong"
str4 db "KeepsGoing"
str5 db "Euphoricly"
str6 db "Rainbowish"
str7 db "Wonderment"
str8 db "activeness"
str9 db "winterless"
str10 db "guarantied"
;输入的串
istr db 11,0,11 dup('$')
;背景加前景色
pinkBlack equ 50H
blackWhite equ 0fH
blackRed equ 0cH
blackYellow equ 0eh
blackGreen equ 0ah
blackGrey equ 07h
;记录
hscore db 0
score db 100
ends
stack segment
dw 128 dup(0)
ends
code segment
start:
; set segment registers:
mov ax, data
mov ds, ax
mov es, ax
; add your code here
;光标位置
setCursorP macro row,col
push ax
push dx
push bx
mov dh,row
mov dl,col
mov bh,0
mov ah,02h
int 10h
pop bx
pop dx
pop ax
endm
;在光标处打印字符
printChar macro char,attribute,times
push ax
push bx
push cx
mov al,char
mov bh,0
mov bl,attribute
mov cx,times
mov ah,09h
int 10h
pop cx
pop bx
pop ax
endm
;上滚
scroll macro N,TOP,LEFT,BUTTOM,RIGHT,ATTRIBUTE
push ax
push bx
push cx
push dx
mov bh,ATTRIBUTE ;形式
mov ch,TOP
mov cl,LEFT
mov dh,BUTTOM
mov dl,RIGHT
mov ah,06h
mov al,N ;上卷数
int 10h
pop dx
pop cx
pop bx
pop ax
endm
;下滚
scrollDown macro N,TOP,LEFT,BUTTOM,RIGHT,ATTRIBUTE
push ax
push bx
push cx
push dx
mov bh,ATTRIBUTE ;形式
mov ch,TOP
mov cl,LEFT
mov dh,BUTTOM
mov dl,RIGHT
mov ah,07h
mov al,N ;上卷数
int 10h
pop dx
pop cx
pop bx
pop ax
endm
;画背景
getBackground macro
scroll 0,0,0,24,79,02
scroll 79,bg[0],bg[1],bg[2],bg[3],pinkBlack
scroll 79,bg[4],bg[5],bg[6],bg[7],blackWhite
endm
;在光标位置输入字符
inputChar macro
mov ah,0h
int 16h
endm
;得到当前时间(用dos调用)
getTime macro
push ax
push cx
push dx
mov ah,2ch
int 21h
mov min,cl
mov second,dh
mov persecond,dl
pop dx
pop cx
pop ax
endm
;打印游戏时间(光标已移到正确的位置)
printGameTime macro
local msNoChange,sNoChange,mNoChange
push ax
push bx
push cx
push dx
;得到光标位置
mov bh,0
mov ah,03h
int 10h ;;DH/DL =行号/列号
and cx,0
mov cl,dh ;;行号
and dh,0
push cx
push dx ;行和列号调用printNum 用
mov dl,perSecond
mov dh,min
mov ch,second
getTime ;;得到当前新的时间
mov bl,min ;分
;秒结果在ax中
;msec在cl中
mov al,second
mov cl,persecond
sub cl,dl
jns msNoChange
add cl,100
msNoChange:
sbb al,ch
pushf
jns sNoChange ;>0不改
;改
add al,60
sNoChange:
popf
sbb bl,dh
jns mNoChange
add bl,60
mNoChange:
and ah,0
and ch,0
and bh,0
push bx
call printNum ;打印分
printChar ':',blackWhite,1
;得到光标位置
push cx
mov bh,0
mov ah,03h
int 10h ;;DH/DL =行号/列号 cx:属性
inc dl ;列加1
mov cl,dh
and ch,0
and dh,0
push cx ;行
push dx ;列
push ax ;打印秒
call printNum
printChar ':',blackWhite,1
;得到光标位置
mov bh,0
mov ah,03h
int 10h ;;DH/DL =行号/列号 cx:属性
inc dl ;列加1
mov cl,dh
and ch,0
and dh,0
pop bx
push cx ;行
push dx ;列
push bx
call printNum ;打印perSecond
printChar '0',blackGreen,1
pop dx
pop cx
pop bx
pop ax
endm
;主程序
;开屏
mov al,02h
mov ah,0h
int 10h
;光标样式
mov ah,01h
mov ch,06h
mov cl,07h
int 10h
;要有一个死循环
mainWhile:
;画背景
getBackground
call welcome
inputChar ;输入功能号
cmp al,op1
jz STARTGAME
cmp al,op2
jz RECORD
cmp al,op3
jz FINISH
call opError ;输入功能号错误
jmp mainWhile
jmp FINISH
STARTGAME:
call gameProc ;启动游戏
RECORD:
call recordProc ;查看最高分
jmp mainWhile ;死循环
FINISH:
mov ax, 4c00h ; exit to operating system.
int 21h
;在光标处打印字符串
;str地址 18
;str长度 16
;row+col 14
;属性 12
;出口
;ax
;bx
;cx
;dx
;bp [sp]
printStr proc ;要push str地址,row,col
push ax
push bx
push cx
push dx
push bp
mov bp,sp
mov cx,[bp+16]
mov bh,0
mov al,0
mov bl,[bp+12]
mov dx,[bp+14]
push bx
mov bx,[bp+18]
mov bp,bx
pop bx
mov ah,13h
int 10h
pop bp
pop dx
pop cx
pop bx
pop ax
ret 8
endp
;欢迎语句
welcome proc
push ax
push cx
push dx
mov ch,bg[4]
mov cl,bg[5]
inc ch
inc cl
push offset welcome1
push lwelcome1
push cx
push blackWhite
call printStr
inc ch
push offset welcome2
push lwelcome2
push cx
push blackWhite
call printStr
inc ch
push offset option1
push loption1
push cx
push blackWhite
call printStr
inc ch
push offset option2
push loption2
push cx
push blackWhite
call printStr
inc ch
push offset option3
push loption3
push cx
push blackWhite
call printStr
inc ch
setCursorP ch,cl
pop dx
pop cx
pop ax
ret
endp
;启动游戏
gameProc proc
getBackground
mov ch,bg[4]
inc ch
mov cl,center[1]
shr cl,1 ;col在1/4
setCursorP ch,cl
push offset gameHint
push lgameHint
push cx
push blackWhite
call printStr
;开始计时
getTime
mov dl,0 ;dl:字符串循环次数为10
mov bx,0 ;bx存输出的字符串起始下标
printSample: ;打样例
mov ch,center[0]
mov cl,center[1]
sub cl,5
setCursorP ch,cl ;row为1/2,col为中心点-5
printChar '*',blackYellow,1
inc cl
;打字符串
setCursorP ch,cl
lea ax,str1[bx]
push ax
push lstr
push cx
push blackWhite
call printStr
inc ch
dec cl
setCursorP ch,cl
printChar '#',blackWhite,1
;打字
mov dh,0 ;打lstr个字符
lea si,str1[bx] ;si是对应的答案
inputStr:
inc cl
setCursorP ch,cl
inputC:
inputChar
printChar al,blackGrey,1
inputJudge: ;判断打的字
cmp al,op3 ;是否是退出
jnz NEXTCHAR
;是退出键
push cx
call isExit
cmp al,op1
jnz noChoose
;选择退出
jmp MainWhile
noChoose:
;不退出
pop cx
push cx
push cx
call noExit
pop cx
jmp inputC
NEXTCHAR:
;cmpsb
cmp al,[si]
jz INPUTRIGHT
;输入错误
;add cl,dh
inc ch ;光标向下移
setCursorP ch,cl
printChar [si],blackRed,1
;sub cl,dh
dec ch
dec score ;得分减1
INPUTRIGHT:;正确
inc si
inc dh
cmp dh,lstr
jnz inputStr
;打了几个字符串
add bx,lstr
inc dl
;上卷
push cx
mov ax,cx
add ah,2
add al,lstr
mov ch,center[0]
sub ch,4
mov cl,center[1]
sub cl,10
scroll 4,ch,cl,ah,al,blackGrey
pop cx
cmp dl,lstr
jnz printSample
;游戏结束
;得到时间
mov ch,center[0]
mov cl,center[1]
sub cl,10
setCursorP ch,cl ;row为1/2,col为1/4中心点-10
printChar '*',blackYellow,1
inc cl
mov ax,offset gameTimeHint
push ax
push lgameTimeHint
push cx
push blackWhite
call printStr
add cl,lgameTimeHint
setCursorP ch,cl
printGameTime
;是否是最高分
mov cl,score
cmp cl,hscore
jbe outputRes
mov hscore,cl
;得到结果
outputRes:
inc ch
mov cl,center[1]
sub cl,10
setCursorP ch,cl ;row为1/2,col为1/4中心点-10
printChar '*',blackYellow,1
inc cl
mov ax,offset scoreHint
push ax
push lscoreHint
push cx
push blackWhite
call printStr
add cl,lscoreHint
setCursorP ch,cl
mov ax,cx
and ah,0
mov cl,ch
and ch,0
push cx
push ax
and ax,0
mov al,score
push ax
mov ch,cl
mov cl,al
call printNum ;输出分数
;按任意键返回
inc ch
mov cl,center[1]
sub cl,10
setCursorP ch,cl ;row为1/2,col为1/4中心点-10
printChar '*',blackYellow,1
inc cl
mov ax,offset gameOver
push ax
push lgameOver
push cx
push blackWhite
call printStr
inc ch
setCursorP ch,cl
inputChar
ret
endp
;查看最高分的子程序
recordProc proc
getBackground
mov ch,center[0]
mov cl,center[1]
sub cl,10
setCursorP ch,cl ;row为1/2,col为1/4中心点-10
printChar '*',blackYellow,1
inc cl
mov ax,offset hscoreHint
push ax
push lhscoreHint
push cx
push blackWhite
call printStr
add cl,lhscoreHint
setCursorP ch,cl
mov ax,cx
and ah,0
mov cl,ch
and ch,0
push cx
push ax
and ax,0
mov al,hscore
push ax
mov ch,cl
mov cl,al
call printNum ;输出分数
;按任意键返回
inc ch
mov cl,center[1]
sub cl,10
setCursorP ch,cl ;row为1/2,col为1/4中心点-10
printChar '*',blackYellow,1
inc cl
mov ax,offset anyKeyExit
push ax
push lanyKeyExit
push cx
push blackWhite
call printStr
inc ch
setCursorP ch,cl
inputChar
ret
endp
;按到退出的子程序
isExit proc
;上卷
mov ax,cx
add ah,2
add al,lstr
mov ch,center[0]
sub ch,4
mov cl,center[1]
sub cl,6
scroll 4,ch,cl,ah,al,blackGrey
mov ch,center[0]
mov cl,center[1]
sub cl,10
setCursorP ch,cl ;row为1/2,col为1/4中心点-10
printChar '*',blackYellow,1
inc cl
;打字符串
setCursorP ch,cl
mov ax,offset exitHint
push ax
push lexitHint
push cx
push blackRed
call printStr
inc ch
inc cl
setCursorP ch,cl
mov ax,offset exitOption1
push ax
push lexitOption1
push cx
push blackGrey
call printStr
inc ch
setCursorP ch,cl
mov ax,offset exitOption2
push ax
push lexitOption2
push cx
push blackGrey
call printStr
inc ch
setCursorP ch,cl
sub cl,2
inputChar
ret
endp
;选择不退出的子程序
;cx 4
;出口
;bp [sp]
noExit proc
;下滚
push bp
mov bp,sp
mov ch,center[0]
mov cl,center[1]
mov ax,cx
add ah,3
add al,10
sub ch,4
sub cl,10
scrollDown 4,ch,cl,ah,al,blackGrey
;恢复上一个字符
mov cx,[bp+4]
setCursorP ch,cl
printChar ' ',blackGrey,1
pop bp
ret 2
endp
;打印数字的程序
;光标row 16
;col 14
;数字 12
;出口
;bp
;ax
;bx
;cx
;dx [sp]
printNum proc
push bp
push ax
push bx
push cx
push dx
mov bp,sp
mov ax,[bp+12] ;得到数字
and cx,0
mov bx,[bp+16] ;bl存:row
mov dx,[bp+14] ;dl存:col
setCursorP bl,dl
and dh,0
mov bh,10 ;bh:存10
continueDiv:
and ah,0
div bh
;余数在ah(小于10),商在al
add ah,'0'
mov cl,ah ;cl:记录结果
inc dh ;dh:有几个数
push cx ;存结果
cmp al,0
jnz continueDiv ;除法的循环
;循环结束
outPutNum:
pop cx
printChar cl,blackGreen,1
inc dl ;光标往后
setCursorP bl,dl
dec dh
jnz outPutNum ;输出的循环
pop dx
pop cx
pop bx
pop ax
pop bp
ret 6
endp
;输入功能号错误
opError proc
getBackground
mov ch,center[0]
mov cl,center[1]
sub cl,10
setCursorP ch,cl ;row为1/2,col为1/4中心点-10
printChar '*',blackYellow,1
inc cl
mov ax,offset opErrorHint
push ax
push lopErrorHint
push cx
push blackWhite
call printStr
;按任意键返回
inc ch
mov cl,center[1]
sub cl,10
setCursorP ch,cl ;row为1/2,col为1/4中心点-10
printChar '*',blackYellow,1
inc cl
mov ax,offset anyKeyExit
push ax
push lanyKeyExit
push cx
push blackWhite
call printStr
inc ch
setCursorP ch,cl
inputChar
ret
endp
ends
end start ; set entry point and stop the assembler.