assume cs:code,ss:stack
stack segment
db 128 dup (0)
stack ends
code segment
;---------------------------- 安装程序 ----------------------------------------
start:
mov ax,stack
mov ss,ax
mov sp,128
;将引导程序安装到磁盘0面0磁道1扇区
mov bx,cs
mov es,bx
mov bx,offset setup
mov ch,0
mov cl,1
mov dh,0
mov dl,0
mov ah,3
mov al,1
int 13h
;将任务程序安装到磁盘0面0磁道2扇区
mov bx,cs
mov es,bx
mov bx,offset boot
mov ch,0
mov cl,2
mov dh,0
mov dl,0
mov ah,3
mov al,2
int 13h
mov ax,4c00h
int 21h
;------------------------ 引导程序 -------------------------------------------
setup:
mov bx,0
mov ss,bx
mov sp,7C00H
call installint9 ;将原int9地址保存到0:200H处
call installboot ;将任务程序从磁盘0面0磁道2扇区安装到0:7C00H处
mov bx,0
push bx
mov bx,7E00H
push bx
retf ;引导安装完成后,从0:7E00H执行任务程序
;安装新的int9
installint9:
push cs
push es
mov ax,cs
mov ds,ax
mov si,offset newint9 - offset setup + 7C00H
mov ax,0
mov es,ax
mov di,206H
mov cx,offset newint9end - offset newint9
cld
rep movsb
pop es
pop cx
ret
;新int9中断
newint9:
push ax
push bx
push cx
push es
in al,60H
pushf
call dword ptr cs:[200H]
cmp al,3BH
je int9_f1
cmp al,1
je int9_esc
jmp short newint9ret
;响应F1的子程序
int9_f1:
mov ax,0B800H
mov es,ax
mov bx,1
mov cx,2000
int9_f1s:
inc byte ptr es:[bx]
add bx,2
loop int9_f1s
jmp short newint9ret
;响应ESC的子程序
int9_esc:
mov ax,0
mov es,ax
cli
push es:[200H]
pop es:[9*4]
push es:[202H]
pop es:[9*4+2]
sti
mov word ptr es:[204],1 ;设置用于中断显示时间循环的flag
jmp short newint9ret
newint9ret:
pop es
pop cx
pop bx
pop ax
iret
newint9end:
nop
;安装任务程序
installboot:
mov bx,0
mov es,bx
mov bx,7E00H
mov ch,0
mov cl,2
mov dh,0
mov dl,0
mov ah,2
mov al,2
int 13h
ret
db 512 dup (0) ;安装程序将引导程序安装到磁盘后,第一个扇区空闲位置用0补足
;---------------------------- 任务程序 ----------------------------------------
boot:
jmp short menu
s1 db '1) reset pc',0
s2 db '2) start system',0
s3 db '3) clock',0
s4 db '4) set clock',0
s5 db 'Enter index number:',0
show dw offset s1 - offset boot + 7E00H
dw offset s2 - offset boot + 7E00H
dw offset s3 - offset boot + 7E00H
dw offset s4 - offset boot + 7E00H
dw offset s5 - offset boot + 7E00H
time db '00/00/00 00:00:00',0
cindex db 9,8,7,4,2,0
;调用菜单
menu:
mov bx,0B800H
mov es,bx
mov bx,0
mov ds,bx
call cls
call line
jmp short run
;清屏程序
cls:
push es
mov bx,0B800H
mov es,bx
mov bx,0
mov cx,2000
clss:
mov ax,0720H
mov es:[bx],ax
add bx,2
loop clss
pop es
ret
;显示文字数据
line:
mov bx,offset show - offset boot + 7E00H ;文字行地址
mov cx,5
mov di,160*8+30*2
lines:
mov si,ds:[bx] ;ds:[bx]为文字行首字符地址,si为文字行第一个字符的地址
call showline
add di,160
add bx,2
loop lines
ret
;显示一行字符串
showline:
push di
showlines:
mov al,ds:[si]
cmp al,0
je showlineok
mov es:[di],al
add di,2
inc si
jmp short showlines
showlineok:
pop di
ret
;响应菜单指令程序
run:
call clearbuff
mov ah,0
int 16h
cmp al,'1'
je f1
cmp al,'2'
je f2
cmp al,'3'
je f3
cmp al,'4'
je f4
jmp run
;清除输入缓存
clearbuff:
mov ah,1 ;读取键盘缓存字符,返回参数ZF=0时al=字符,ZF=1时缓存区为空
int 16h
jz clearbuffok ;ZF=1时缓存区为空跳转
mov ah,0 ;ZF不为1时,循环读取字符并丢弃al
int 16h
jmp clearbuff
clearbuffok:
ret
;响应指令1
f1:
call showi
call reboot
;mov word ptr ds:[0],0FFFFH
;mov word ptr ds:[2],0
;call dword ptr ds:[0]
jmp run
;响应指令2
f2:
call showi
call system
;响应指令3
f3:
call showi
call gettime
jmp menu
;响应命令4
f4:
call showi
call settime
jmp menu
;显示输入的命令序号
showi:
mov byte ptr es:[160*12+30*2+19*2],al
ret
;重启
reboot:
mov bx,0FFFFH
push bx
mov bx,0
push bx
retf
;加载c盘系统并执行
system:
mov bx,0
mov es,bx
mov bx,7C00H
mov ch,0
mov cl,1
mov dl,80h
mov dh,0
mov ah,2
mov al,1
int 13h
call cls
mov bx,0
push bx
mov bx,7C00H
push bx
retf
;设定cmos时间程序
settime:
call resettimedata
call showtimedata
call getstr
call updatetime
ret
;更新cmos时间程序
updatetime:
mov bx,offset cindex - offset boot + 7E00H
mov si,offset time - offset boot +7E00H
mov cx,6
updatetimes:
push cx
mov dx,ds:[si]
sub dx,3030H
mov cl,4
shl dl,cl
or dl,dh
mov al,ds:[bx]
out 70h,al
mov al,dl
out 71h,al
add si,3
inc bx
pop cx
loop updatetimes
ret
;将输入内容存储到时间字符串缓存
getstr:
mov si,offset time - offset boot + 7E00H ;字符栈缓存位置
mov bx,0 ;字符栈当前位置
getstrs:
call clearbuff
mov ah,0
int 16h
cmp al,'0'
jb notnumber
cmp al,'9'
ja notnumber
call charpush
call showtimedata
jmp getstrs
;非数字时,判断是否为backspaces或enter
notnumber:
cmp ah,0eh
je backspace
cmp ah,1ch
je enter
jmp getstrs
;退格键执行
backspace:
call charpop
call showtimedata
jmp getstrs
;回车键执行(结束输入)
enter:
ret
;字符栈出栈
charpop:
cmp bx,0
je charpopret
cmp bx,3
je charreset
cmp bx,6
je charreset
cmp bx,9
je charreset
cmp bx,12
je charreset
cmp bx,15
je charreset
cmp bx,1
je chargo
cmp bx,2
je chargo
cmp bx,4
je chargo
cmp bx,5
je chargo
cmp bx,7
je chargo
cmp bx,8
je chargo
cmp bx,10
je chargo
cmp bx,11
je chargo
cmp bx,13
je chargo
cmp bx,14
je chargo
cmp bx,16
je chargo
cmp bx,17
je chargo
charreset:
dec bx
chargo:
dec bx
mov byte ptr ds:[si+bx],'0'
cmp bx,3
je charpopset
cmp bx,6
je charpopset
cmp bx,9
je charpopset
cmp bx,12
je charpopset
cmp bx,15
je charpopset
jmp short charpopret
charpopset
dec bx
charpopret:
ret
;字符栈入栈
charpush:
cmp bx,16
ja charpushret
mov ds:[si+bx],al
inc bx
cmp bx,2
je charpushset
cmp bx,5
je charpushset
cmp bx,8
je charpushset
cmp bx,11
je charpushset
cmp bx,14
je charpushset
jmp short charpushret
charpushset:
inc bx
charpushret:
ret
;显示时间字符串缓存内容
showtimedata:
push si
push di
mov si,offset string_stack - offset boot + 7E00H
mov di,160*14+30*2
call showline
pop di
pop si
ret
;重置时间字符串内容
resettimedata:
push bx
push cx
push es
push si
push di
mov si,offset time - offset boot + 7E00H
mov dx,3030h
mov cx,6
clearstringstack:
mov ds:[si],dx
add si,3
loop clearstringstack
pop di
pop si
pop es
pop cx
pop bx
ret
;显示cmos时间程序
gettime:
call setupnewint9
call showtime
ret
;安装新的int9程序
setupnewint9:
push es
mov ax,0
mov es,ax
push es:[9*4]
pop es:[200H]
push es:[9*4+2]
pop es:[202H]
cli
mov word ptr es:[9*4],206H
mov word ptr es:[9*4+2],0
sti
mov word ptr es:[204H],0 ;初始化响应ESC的flag
pop es
ret
;显示时间字符串
showtime:
push ax
push bx
push cx
push es
showtimestart:
call clearibuff
mov cx,6
mov si,0
mov di,0
showtimes:
mov bx,offset cindex - offset install + 7E00H
mov al,ds:[bx+si]
call savetimedata ;将读取结果保存到时间字符串缓存中,用于显示。若为读取并马上显示,会发生闪烁现象
add di,3
inc si
loop showtimes
mov ah,al
mov al,0
out 70H,al
in al,71H
cmp al,ah
je showtime
mov bx,offset time - offset install + 7E00H
call showdata
mov ax,0
mov es,ax
mov ax,es:[204H]
cmp ax,1
je showtimeok ;每个循环中判断响应ESC的flag是否为1,为1则中断循环
jmp short showtimestart
showtimeok:
pop es
pop cx
pop bx
pop ax
ret
;把读取的cmos数据保存到时间字符串缓存
savetimedata:
push cx
out 70H,al
in al,71H
mov ah,al
mov cl,4
shr ah,cl
and al,00001111B
add ax,3030H
mov bx,offset time - offset install + 7E00H
mov ds:[bx+di],ah
mov ds:[bx+di+1],al
pop cx
ret
;显示时间字符串
showdata:
push ax
push cx
push es
mov ax,0B800H
mov es,ax
mov di,160*16+30*2
mov si,0
mov cx,17
showdatas:
mov al,ds:[bx+si]
mov byte ptr es:[di],al
inc si
add di,2
loop showdatas
pop es
pop cx
pop ax
ret
db 512 dup (0)
code ends
end start
王爽 著《汇编语言》(第3版):课程设计2
最新推荐文章于 2022-07-26 16:53:25 发布