先来看看效果图吧
本实验 来源于《汇编语言》-王爽,本次课设在XP系统下进行,若要测试请安装虚拟机XP系统
这是汇编实现的源代码,我也是初学汇编,有什么写的不好的地方请见谅
assume cs:code
code segment
start:
mov ax,cs
mov es,ax
mov bx,offset mpc
mov al,6 ;xie扇区数
mov ch,0 ;磁道号
mov cl,1 ;扇区号
mov dl,0 ;驱动器号
mov dh,0 ;磁头号
;es:bx指向从内存写入扇区的内存地址
mov ah,3 ;ah为功能号 3为写扇区 2为读扇区
int 13h
mov ax,4c00h
int 21h
mpc:
jmp mstart
dw offset charpush-offset mpc+7c00h,offset charpop-offset mpc+7c00h,offset charshow-offset mpc+7c00h
dw 0 ;栈顶
db 32 dup(0) ;栈中的字符
db '1) reset pc ',0
db '2) start system',0
db '3) clock ',0
db '4) set clock ',0
dw 0,0,0,0,0,0 ;年月日,时分秒 88+16
db 9,8,7,4,2,0 ;119
db 'F1 to charge color, ESC to end',0 ;125
db 'year/month/day/hour/minute/sec,press enter to continue',0;122+31
db 'Input function number and press enter to confirm ',0 ;125+31+55
mstart:
mov ax,0
mov es,ax
mov bx,7c00h+512
mov al,5 ;读取扇区数
mov ch,0 ;磁道号
mov cl,2 ;扇区号
mov dl,0 ;驱动器号
mov dh,0 ;磁头号
;es:bx指向从扇区读入的内存区
mov ah,2 ;ah为功能号 3为写扇区 2为读扇区
int 13h
mpcstart:
mov dh,4
mov dl,0
mov bx,125+31+55+7c00h ;############
call ackshowstr
call showchoice
call getstr
mov ah,cs:[8+7c00h+3] ;字符存储地址##################
cmp ah,'3'
je clockcall
cmp ah,'4'
je setclockcall
cmp ah,'1'
je resetpc
cmp ah,'2'
je startsyscall
jmp mpcstart
clockcall:
call clearhint
call clock
jmp mpcstart
setclockcall:
call clearhint
call setclock
jmp mpcstart
startsyscall:
call startsys
;///clearhint
clearhint:
push ax
push bx
push cx
push es
mov ax,0b800h
mov es,ax
mov bx,4*160
mov cx,64
hintloop:
mov byte ptr es:[bx],0
add bx,2
loop hintloop
pop es
pop cx
pop bx
pop ax
ret
;///1号功能 重启计算机
resetpc:
mov word ptr ds:[0],0
mov word ptr ds:[2],0ffffh
jmp dword ptr ds:[0] ;计算机重启地址############
;///3号功能 显示时间
clock:
push ax
push bx
push cx
push dx
mov dh,4
mov dl,0
mov bx,125+7c00h ;############
call ackshowstr
call getclockime
call showclocktime
mov cx,cs:[98+16+7c00h+3] ;秒地址############
mov bx,1
clocks0:
call isquit
cmp bx,0
je clockend
call getclockime
mov dx,cs:[98+16+7c00h+3] ;秒地址##########
cmp cx,dx
jne clocknext0
jmp clocks0
clocknext0:
call showclocktime
mov cx,dx
jmp clocks0
clockend:
mov bl,2 ;调用ack提示并等待回车
call ack
pop dx
pop cx
pop bx
pop ax
ret
getclockime: ;获取时间
push cx
push ax
push si
push di
push ds
push es
push bx
push dx
mov si,100+16+7c00h+3 ;时间信息端口读取地址####
mov di,88+16+7c00h+3 ;存储时间地址#########
mov cx,6
s:
push cx
mov al,cs:[si]
out 70h,al
in al,71h
mov ah,al
mov cl,4
shr ah,cl
and al,00001111b
add ah,30h
add al,30h
mov cs:[di],ah
mov cs:[di+1],al
inc si
add di,2
pop cx
loop s
pop dx
pop bx
pop es
pop ds
pop di
pop si
pop ax
pop cx
ret
showclocktime: ;显示时间
push cx
push ax
push si
push di
push ds
push es
push bx
push dx
mov ax,0b800h
mov es,ax
mov si,5*160
mov di,88+16+7c00h+3 ;时间地址#######
mov cx,6
s1:
mov ah,cs:[di]
mov es:[si],ah
add si,2
inc di
mov ah,cs:[di]
mov es:[si],ah
add si,2
inc di
cmp cx,1
je ed
cmp cx,3
jna s2
mov al,2fh ;/
jmp next
s2:
mov al,3ah ;:
next:
mov es:[si],al
add si,2
loop s1
ed:
pop dx
pop bx
pop es
pop ds
pop di
pop si
pop ax
pop cx
ret
isquit: ;bx0退出 bx为1继续
push ax
push cx
in al,60h
cmp al,01h ;若为esc 退出循环
je yesquit
cmp al,3bh ;若为f1 改变颜色
je changecolor
mov bx,1
jmp isquitend
yesquit:
mov bx,0
jmp isquitend
changecolor:
mov si,5*160+1
mov ax,0b800h
mov es,ax
mov cx,17
chagecolors:
cmp byte ptr es:[si],7
ja clearzero
inc byte ptr es:[si]
chagenext:
add si,2
loop chagecolors
mov bx,1
jmp isquitend
clearzero:
mov byte ptr es:[si],1
jmp chagenext
isquitend:
pop cx
pop ax
ret
;///4号功能 设置时间 设置格式 19/12/13/12:51:42
setclock:
push cx
push ax
push si
push di
mov dh,4
mov dl,0
mov bx,125+31+7c00h ;############
call ackshowstr
call getstr
mov si,100+16+7c00h+3 ;时间信息端口数地址########
mov di,8+7c00h+3 ;字符串空间存储地址#########
mov cx,6
setclocks:
push cx
mov ax,cs:[di]
sub ah,30h
sub al,30h
cmp ah,9
ja nonumber
cmp al,9
ja nonumber
mov cl,4
shl ah,cl
or ah,al
mov al,cs:[si]
out 70h,al
mov al,ah
out 71h,al
inc si
add di,3
pop cx
loop setclocks
mov bl,0
call ack
setclockend:
pop di
pop si
pop ax
pop cx
ret
nonumber:
pop cx
mov bl,1
call ack
jmp setclockend
;///显示功能
showchoice:
push cx
push ax
push dx
push bx
mov ax,0b800h
mov es,ax
mov cx,4
mov bx,40+7c00h+3 ;功能行字符串起始地址###########
mov dh,0
showchoices0:
call showstart
add bx,16
inc dh
loop showchoices0
showchoicend:
pop bx
pop dx
pop ax
pop cx
ret
showstart: ;dh为行 dl为列40 cs:bx为起始位置
push bx
push dx
push ax
mov dl,0
mov al,160
mul dh
mov di,ax
add dl,dl
mov dh,0
add di,dx
showstarts:
cmp byte ptr cs:[bx],0
je showend
mov ah,byte ptr cs:[bx]
mov es:[di],ah
mov byte ptr es:[di+1],00001001b
inc bx
add di,2
jmp showstarts
showend:
pop ax
pop dx
pop bx
ret
;///读取输入字符串的程序
getstr:
push ax
push bx
push cx
;清空即将输入的地方
mov ax,0b800h
mov es,ax
mov bx,5*160
mov cx,32
getstrloop:
mov byte ptr es:[bx],0
add bx,2
loop getstrloop
mov word ptr cs:[6+3+7c00h],0 ;清空栈##################
getstrs:
mov ah,0
int 16h
cmp al,20h ;ascll小于20h 说明不是字符
jb nochar
mov ah,0
call charstack ;字符入栈
mov ah,2
call charstack ;显示栈中的字符
jmp getstrs
nochar:
cmp ah,0eh ;退格键的扫描码
je backspace
cmp ah,1ch ;enter 键扫描码
je enter
jmp getstrs ;其他键不做处理
backspace:
mov ah,1
call charstack ;字符出栈
mov ah,2
call charstack ;
jmp getstrs
enter:
mov al,0
mov ah,0
call charstack ;0入栈
mov ah,2
call charstack ;显示栈中的字符
pop cx
pop bx
pop ax
ret
;存储字符串子程序
charstack:
jmp charstart
charstart:
push bx
push dx
push di
push es
push cx
cmp ah,2
ja sret
mov di,6+7c00h+3 ;存放栈顶值的偏移地址#############
mov si,8+7c00h+3 ;存放栈开始的地址##############
mov bl,ah
mov bh,0
add bx,bx
add bx,3+7c00h ;#################
jmp word ptr cs:[bx]
charpush:
cmp word ptr cs:[di],17 ;是否超出存储空间
je sret
mov bx,cs:[di] ;bx=栈顶值
mov cs:[si][bx],al ;al 入栈
inc word ptr cs:[di]
jmp sret
charpop:
cmp word ptr cs:[di],0
je sret
dec word ptr cs:[di]
mov al,cs:[si][bx]
jmp sret
charshow:
push di
pop cx ;cx存放栈顶值的偏移地址
mov bx,0b800h
mov es,bx
mov al,160
mov dh,5 ;di为 4 行 0列
mov dl,0
mul dh
mov di,ax
add dl,dl
mov dh,0
add di,dx
mov bx,0
charshows:
push di ;保存行列地址
mov di,cx
cmp bx,cs:[di]
jne noempty
pop di
mov byte ptr es:[di],' '
jmp sret
noempty:
pop di ;di为行列地址
mov al,cs:[si][bx]
mov es:[di],al
mov byte ptr es:[di+1],00000111b
inc bx
add di,2
jmp charshows
sret:
pop cx
pop es
pop di
pop dx
pop bx
ret
;2号功能 引导现有操作系统
startsys:
mov ax,0
mov es,ax
mov bx,7c00h
mov al,1 ;读取扇区数
mov ch,0 ;磁道号
mov cl,1 ;扇区号
mov dl,80h ;驱动器号
mov dh,0 ;磁头号
;es:bx指向从扇区读入的内存区
mov ah,2 ;ah为功能号 3为写扇区 2为读扇区
int 13h
mov word ptr ds:[0],7c00h
mov word ptr ds:[2],0
jmp dword ptr ds:[0] ;操作系统起始地址###########
;/ack 回应清空键盘缓冲区 bl为功能号调用不同字符串
ack:
jmp ackstart
str1: db'set success,press Enter to return',0
str2: db'set failed:formal error,press Enter to return',0
str3: db'press Enter to return',0
adr:dw offset str1-offset mpc+7c00h,offset str2-offset mpc+7c00h,offset str3-offset mpc+7c00h ;#####
ackstart:
push ax
push bx
push cx
push dx
push es
mov bh,0
add bl,bl
add bx,offset adr-offset mpc+7c00h ;########
mov bx,cs:[bx]
mov dh,6 ;6行0列
mov dl,0
call ackshowstr
acknext: ;等待回车
mov ah,0
int 16h
cmp ah,1ch ;为回车键的扫描码
je ackend
jmp acknext
ackend:
;清空提示4行5行与6行的提示
mov ax,0b800h
mov es,ax
mov bx,4*160
mov cx,64
ackloop:
mov byte ptr es:[bx],0
add bx,2
loop ackloop
mov bx,5*160
mov cx,32
ackloop1:
mov byte ptr es:[bx],0
mov byte ptr es:[bx+1],00000111b
add bx,2
loop ackloop1
mov bx,6*160
mov cx,64
ackloop2:
mov byte ptr es:[bx],0
add bx,2
loop ackloop2
pop es
pop dx
pop cx
pop bx
pop ax
ret
;///
ackshowstr: ;cs:bx为字符串起始地址
push ax
push bx
push cx
push dx
push es
push di
mov ax,0b800h
mov es,ax
mov al,160
mul dh
mov di,ax
add dl,dl
mov dh,0
add di,dx
ackstrloop:
cmp byte ptr cs:[bx],0
je ackshowstrend
mov al,cs:[bx]
mov es:[di],al
inc bx
add di,2
jmp ackstrloop
ackshowstrend:
pop di
pop es
pop dx
pop cx
pop bx
pop ax
ret
code ends
end start
基本上注释了 所有逻辑,有疑惑的朋友可以加我qq1023499413 探讨