程序的功能
(1)列出功能选项,让用户通过键盘进行选择,界面如下
1)reset pc ;重启计算机
2)start system ;引导现有的操作系统
3)clock ;进入时钟程序
4)set clock ;设置时间
(2)用户输入"1"后重新启动计算机
(3)用户输入"2"后引导现有的操作系统
(4)用户输入"3"后,执行动态显示当前日期、时间的程序
(5)当用户输入"4"后可更改当前的日期、时间,更改后返回到主选单(输入字符串)
这是个半成品,限于能力有限,未能实现第二部功能
代码如下
assume cs:code,ss:stack
stack segment
db 128 dup (0)
stack ends
code segment
start:
mov bx,stack
mov ss,bx
mov sp,128
call copy_boot
mov bx,0
push bx
mov bx,7c00H
push bx
retf
mov ax,4C00H
int 21H
;================================================================
boot:
jmp boot_start
;*******************************************************************************************
MENU_1 db " Weclome To Mr.Zou's System ",0
MENU_2 db ' * (1) Reset PC *',0
MENU_3 db ' * (x) Start System (undone) *',0
MENU_4 db ' * (3) ShowClock *',0
MENU_5 db ' * (4) Set Clock *',0
MENU_6 db 'Please Enter Your Choose(number)',0
MENU_ADDRESS dw offset MENU_1 - offset boot + 7c00H
dw offset MENU_2 - offset boot + 7c00H
dw offset MENU_3 - offset boot + 7c00H
dw offset MENU_4 - offset boot + 7c00H
dw offset MENU_5 - offset boot + 7c00H
dw offset MENU_6 - offset boot + 7c00H
time db 'YY/MM/DD hh:mm:ss',0
cmos db 9,8,7,4,2,0
clockone db 'press F1 to change the color, press ESC to return',0
clock2 db 'Please input Date and Time,(YY MM DD hh mm ss):',0
change db 12 dup (0),0
;*******************************************************************************************
boot_start:
call init_reg ;ds、es寄存器初始化
call clear_screen ;清屏与屏幕初始化(包括边框显示)
call show_menu ;显示menu菜单
jmp choose_option ;开始进入选择的循环中去
mov ax,4C00H
int 21H
;================================================================
choose_option:
call clear_keyboard_buffer ;清除键盘缓冲区
mov ah,0
int 16H
;键盘读入数字
cmp al,'1'
je choose_option_one
cmp al,'2'
je choose_option_two
cmp al,'3'
je choose_option_three
cmp al,'4'
je choose_option_four
jmp choose_option
;================================
choose_option_one:
mov ax,2000h
mov es,ax
mov word ptr es:[0],0
mov word ptr es:[2],0ffffh
jmp dword ptr es:[0]
jmp choose_option
choose_option_two:
jmp choose_option
choose_option_three:
call ShowClock
jmp boot_start ;跳回到boot_start清屏,并重新显示
choose_option_four:
call SetClock
jmp boot_start
;=================================================================
SetClock:
call init_reg ;寄存器初始化
call clear_screen ;清屏并重新画边框
call clear_change_stack ;清空存放修改内容的栈缓冲区
;设置显示提示信息的位置为10行15列开始
mov di,160*10+15*2
mov si,offset clock2 - offset boot + 7c00H
call show_line
;显示修改缓冲区中的内容
mov di,160*12+30*2
mov si,offset change - offset boot + 7c00H
call show_line
call get_string
call set_CMOSRAM
ret
;=================================================================
set_CMOSRAM:
mov bx,offset cmos - offset boot + 7c00H
mov si,offset change - offset boot + 7c00H
mov cx,6
ChangeMessage: ;GetMessage的逆过程
push cx
mov dx,ds:[si]
sub dx,3030H
mov cl,4
shl dl,cl
and dh,00001111B
or dl,dh
mov al,ds:[bx]
out 70H,al ;将al送入地址端口70h
mov al,dl
out 71H,al ; 将数据写入CMOSRAM时钟
inc bx
add si,2
pop cx
loop ChangeMessage
ret
;=================================================================
get_string:
mov si,offset change - offset boot + 07c00H
mov bx,0
getSting:
mov ah,0
int 16H
cmp al,'0' ;判断是否是小于'0'
jb noNumber
cmp al,'9' ;判断是否大于'9'
ja noNumber
call char_push
cmp bx,12
ja EnterKey ;超过输入范围就不允许再输,直接结束
mov di,160*12+30*2 ;与SetClock中,显示修改缓冲区中的内容位置相对应
call show_line
jmp getSting
noNumber:
cmp ah,0EH ;退格通码
je BackspaceKey
cmp ah,1CH ;回车通码
je EnterKey
jmp getSting
BackspaceKey:
call char_pop
mov di,160*12+30*2 ;与SetClock中,显示修改缓冲区中的内容位置相对应
call show_line
jmp getSting
EnterKey:
ret
;=================================================================
char_push:
cmp bx,12
ja char_push_over ;大于12则不再入栈,直接返回
mov ds:[si+bx],al ;入栈
inc bx
char_push_over:
ret
char_pop:
cmp bx,0
je char_pop_over
dec bx
mov byte ptr ds:[si+bx],'*'
char_pop_over:
ret
;=================================================================
clear_change_stack:
push bx
push cx
mov bx,offset change - offset boot + 7c00H
mov cx,6
ClearChangeStack:
mov word ptr ds:[bx],'**'
add bx,2
loop ClearChangeStack
pop cx
pop bx
ret
;=================================================================
ShowClock:
call init_reg ;寄存器初始化
call clear_screen ;清屏并重新画边框
mov di,14*160+15*2 ;设置显示提示信息的位置为14行15列开始
mov si,offset clockone - offset boot + 7c00H
call show_line ;显示
ShowClockStart:
call GetTimeMessage ;获取时间信息放到time中去
mov di,10*160+30*2 ;设置显示时间与日期的位置为10行30列开始
mov si,offset time - offset boot + 7c00H
call show_line ;按规则显示
;这里的读取键盘缓冲区是自己完成,我们亦可以在
mov ah,1 ;非阻塞式读取,由于是非阻塞读取,当读取到之后,缓冲区不会清空
int 16H
jz ShowClockStart
cmp ah,3BH
je ChangeColor
cmp al,1BH ;ESC扫描码为1,与设定的功能号有冲突,所以用ASCII码
je ReturnToMainMenu
cmp al,0 ;能到达这一步说明不为F1也不为ESC
jne ClearKeyBuffer ;但是不为0说明一定是有键盘中断产生,就要清除无用的键盘中断
jmp ShowClockStart
;================================
ChangeColor: ;改变颜色
call ChangeShowColor
ClearKeyBuffer:
call clear_keyboard_buffer ;清除非阻塞读取时未清空的缓冲区
jmp ShowClockStart
ReturnToMainMenu: ;退回到choose_option时会清除缓冲区,所以这里不需要清除缓冲区
ret
;================================================================
GetTimeMessage:
mov cx,6
mov bx,offset cmos - offset boot + 7c00H
mov si,offset time - offset boot + 7c00H
GetMessage:
push cx
mov al,ds:[bx]
out 70H,al ;将al送入地址端口70h
in al,71H ;从数据端口71h处读出单元内容
mov ah,al
mov cl,4
shr al,cl ;右移4位
and ah,0FH ;al分成两个表示BCD码值的数据
add ax,3030H ;BCD码+30h=10进制数对应的ASCII码
mov word ptr ds:[si],ax ;ASCII码写入time段
inc bx
add si,3
pop cx
loop GetMessage
ret
;================================================================
ChangeShowColor:
push bx
push cx
mov cx,2000
mov bx,1
loopChangeShowColor:
add byte ptr es:[bx],1
or byte ptr es:[bx],00001000B ;高亮不闪烁设置
and byte ptr es:[bx],10001111B ;背景一直为黑色
add bx,2
loop loopChangeShowColor
pop cx
pop bx
ret
;================================================================
clear_keyboard_buffer:
mov ah,1
int 16H ;修改了ax,所以ZF可能会改变
jz ClearKeyboardBufferOver ;如果非阻塞读取的数据为0则结束
mov ah,0 ;否则,则继续用阻塞的方式清除一次缓冲区字节
int 16H
jmp clear_keyboard_buffer
ClearKeyboardBufferOver:
ret
;================================================================
init_reg:
mov bx,0B800H
mov es,bx
mov bx,0
mov ds,bx
ret
;================================================================
clear_screen:
mov bx,0
mov cx,2000
mov dx,1F00H ;黑屏白字
ClearScreen:
mov es:[bx],dx
add bx,2
loop ClearScreen
mov bx,6*160+10*2
mov cx,60
clear_showframe_UpandDown:
mov byte ptr es:[bx],'#'
mov byte ptr es:[bx+160*9],'#'
add bx,2
loop clear_showframe_UpandDown
mov bx,7*160+10*2
mov cx,8
clear_showframe_LeftandRight:
mov byte ptr es:[bx],'#'
mov byte ptr es:[bx+59*2],'#'
mov byte ptr es:[bx+2],'#'
mov byte ptr es:[bx+59*2-2],'#'
add bx,160
loop clear_showframe_LeftandRight
ret
;================================================================
show_menu:
mov bx,offset MENU_ADDRESS - offset boot + 7c00H
mov di,160*8 + 25*2
mov cx,6
ShowMenu:
mov si,ds:[bx] ;获取输出行信息的偏移地址
call show_line ;给定显示的位置显示一行
add bx,2 ;获取下一条内容的地址
add di,160 ;输出到下一行
loop ShowMenu
ret
;================================================================
show_line:
push ax
push si
push di
ShowLineStart:
mov al,ds:[si] ;获取一个字符
cmp al,0 ;遇到0则输出结束
je ShowLineOver
mov es:[di],al ;遇到的不是0则输出到显示屏上
add di,2
inc si
jmp ShowLineStart
ShowLineOver:
pop di
pop si
pop ax
ret
;================================================================
boot_end:nop
;================================================================
copy_boot: ;将代码段复制到0:7c00H处(正式的写法都需要将代码放到内存中去)
mov bx,cs
mov ds,bx
mov si,offset boot
mov bx,0
mov es,bx
mov di,7c00H
mov cx,offset boot_end - offset boot
cld
rep movsb
ret
;================================================================
code ends
end start