荣誉值:0
信誉值:6
注册日期:2009-07-15 11:17 |
;终于把课程设计2干掉了!自己做的时候也想了非常久,就是那个org和那个什么AA55h的实在是想不通,书上没有。
;结果那些部分就参考了其它高手的代码,这里先感谢一下他们。
;bug:字符栈大小有限,输入过多字符会引起溢出(偷懒,不想加较检功能了^_^)
;不足之处:在屏幕显示字符串最好单独列个“showstring”之类的函数,不然真的挺麻烦的, 我一开
;始没注意这个问题,后来到程序快完工的时候才注意到,发现在屏幕加个string很麻烦,不过到最后懒得改了
;名称:综合模块
;功能:安装程序,实现所有功能
assume cs:code
code segment
;名称:安装模块
;功能:安装程序到软盘
;安装模块开始--------------------------------------------------------------------
start:
mov ax,cs
mov es,ax
mov bx,offset part1
mov al,3 ;写3个扇区,实际引导程序包含2个部分,第一个512字节部分专门是用来导入后面两个512字节(共1024字节,也就是真正的主程序)的内容
mov dh,0 ;0面
mov ch,0 ;0磁道
mov cl,1 ;1扇区
mov dl,0 ;(dl)=0表示a盘
mov ah,3 ;(ah)=3表示写入,把cs:[offset part1]的内容写入到a盘头3个扇区
int 13h
mov ax,4c00h ;返回到dos
int 21h
;安装模块结束--------------------------------------------------------------------
;名称:part1
;说明:第一部分,512字节,负责把第二部分写入到0:7e00
;part1模块开始--------------------------------------------------------------------
org 7c00h
part1:
mov ax,0
mov es,ax
mov bx,7e00h
mov al,2 ;读两个扇区,从软盘启动,int19h只读取一个扇区的内容,剩下的内容需要靠这个“中转程序”读出来。
mov dh,0 ;0面
mov ch,0 ;0磁道
mov cl,2 ;2扇区
mov dl,0 ;(dl)=0表示a盘
mov ah,2 ;(ah)=2表示读取
int 13h
mov ax,0h
push ax
mov ax,7e00h
push ax
retf ;从cs:ip指向0:7e00h,因为0:7c00~0:7e00之间共512字节
calc0: ;以上程序占31字节
nop
db 512-(offset calc0-offset part1)-2 dup (0) ;把计算字节数这种麻烦事交给编译器
dw 0AA55h ;注意!!!!!!!!!!!!!!!!!!!!!!!!!!!!
;结果经过贴主测试,一下网上资料描述属实,我把0aa55h改成0,就无法引导了!
;以下引自网上资料:
;BIOS中断总是把主引导记录所在扇区(硬盘的0头0道1扇区)的内容(包括代码和数据)
;装入内存0000:7C00起始的区域,然后检验该扇区内容的最后两个字节是不是"AA55",
;如果不是,那么对不起,Int 19h将不把控制权交给主引导记录;若是,则主引导记录
;才能获得了控制权了(Int 19h通过跳转指令交转控制权)
;part1模块结束--------------------------------------------------------------------
;名称:part2
;说明:功能主体部分
;part2模块开始--------------------------------------------------------------------
jmp near ptr head
stackchar db 32 dup (0)
table dw charpush,charpop,charshow,l1,l2,l3,l4,timestr ;timemod为第七位
top dw 0
l1 db '1) reset pc',0
l2 db '2) start system',0
l3 db '3) clock',0
l4 db '4) set clock',0
timestr db 'yy:mm:dd hh:mm:ss',0
cmos db 9,8,7,4,2,0
sign db '// :: '
pcreset dd 0ffff0000h
sysadd dd 00007c00h
head:
call cls
mov ax,0b800h
mov es,ax
mov si,10*160+32*2 ;10行32列,si定位列
mov bp,0 ;bp定位行
mov bx,3 ;bx定位l1、l2、l3、l4偏移
call showmenu
reinput:
mov ah,0ch ;调用int21h的0ch子功能,清楚键盘缓冲区的内容,这个内容是书本上没有的,
;本来我想用修改中断向量表的方法解决的,但是我嫌他麻烦,于是就用了这种办法
int 21h
mov ah,0
int 16h
cmp al,'1'
je ppcreset
cmp al,'2'
je sysstart
cmp al,'4'
je timemod
cmp al,'3'
jne reinput
jmp near ptr clockhead
ppcreset:
jmp dword ptr pcreset
;名称:sysstart
;功能:引导现有操作系统
;sysstart模块开始------------------------------------------------------
sysstart:
call cls
mov ax,0
mov es,ax
mov bx,7c00h
mov al,1 ;读1个扇区
mov dh,0 ;0面
mov ch,0 ;0磁道
mov cl,1 ;1扇区
mov dl,80h ;C盘
mov ah,2 ;(ah)=2表示读取
int 13h
jmp dword ptr sysadd
;sysstart模块结束------------------------------------------------------
;名称:showmenu
;功能:显示主菜单
;说明:把这个模块单独列出来,而不是用显示字符串的方式分开列项目,原因是模块化编程思想
;showmenu模块开始------------------------------------------------------
showmenu:
push bp ;bp值最后恢复
mov cx,4
showstart:
push bx
push si
push ax
add bx,bx ;2个字节存放一个偏移地址
mov bx,table[bx] ;将偏移地址存放到bx
shows:
mov ah,cs:[bx] ;ah存放字符ascii码
cmp ah,0
je showret
mov es:[bp+si],ah
inc bx
add si,2
jmp short shows
showret:
pop ax
pop si
pop bx
inc bx
add bp,160
loop showstart
pop bp
ret
;showmenu模块开结束------------------------------------------------------
;函数名称:cls模块
;功能:清屏
;参数返回:无
cls:
push cx
push bx
mov bx,0b800h
mov es,bx
mov cx,2000
mov bx,0
clsloop:
mov byte ptr es:[bx],0
add bx,2
loop clsloop
pop bx
pop cx
ret
;名称:timemod
;功能:修改cmos时间
;timemod模块开始------------------------------------------------------
timemod:
call cls
mov bx,0b800h
mov es,bx
mov bx,7*2
mov bx,table[bx] ;将偏移地址存放到bx
mov si,11*160+31*2
reshow:
mov ah,cs:[bx] ;ah存放字符ascii码
cmp ah,0
je timemodnext
mov es:[si],ah
inc bx
add si,2
jmp short reshow
timemodnext:
mov ax,cs
mov ds,ax
mov dh,12
mov dl,31
mov si,offset stackchar ;这一句非常重要
call getstr
;开始修改时间:
mov cx,6
mov si,0
mov di,offset stackchar
timeloop:
push cx
mov al,cmos[si]
out 70h,al ;通知COMS RAM要读写的端口
mov ah,cs:[di] ;(ah)=年份十位数 (第一次)
sub ah,30h ;得二进制码
mov cx,4
shl ah,cl
mov al,cs:[di+1] ;(al)=年份个位数 (第一次)
sub al,30h ;得二进制码
add al,ah
out 71h,al ;把al写入到指定单元的数据
inc si
add di,3
pop cx
loop timeloop
jmp near ptr head
;timemod模块结束------------------------------------------------------
;名称:clock模块
;功能:显示时间
;clock模块开始------------------------------------------------------
clockhead:
call cls ;显示时间前先清屏
clock:
mov ax,0b800h
mov es,ax
mov cx,6
mov si,0
mov di,0
mov bx,0
sclock:
mov al,cmos[si]
out 70h,al
in al,71h
push cx
mov ah,al
mov ch,0
mov cl,4
shr ah,cl
and al,00001111b
add ah,30h
add al,30h ;ah存放十位数字,al存放个位数字
mov byte ptr es:[160*12+31*2+di],ah
mov byte ptr es:[160*12+31*2+2+di],al
mov ah,sign[bx]
mov byte ptr es:[160*12+31*2+4+di],ah
inc si
inc bx
add di,6
pop cx
loop sclock
;关键代码
in al,60h
cmp al,3bh ;3bh是"F1"键的扫描码
step1:
jne step2
push cx
push bx
push ax
mov bx,0
mov al,es:[bx+1]
inc al
and al,00000111b
mov cx,2000
mov bx,1
s1:
and byte ptr es:[bx],11111000b
or byte ptr es:[bx],al
add bx,2
loop s1
pop ax
pop bx
pop cx
jmp short step3
step2:
cmp al,01h ;01h是"ESC"键的扫描码
;返回主菜单前先清屏
jne step3
call cls
jmp near ptr head
step3:
jmp short clock
;clock模块结束------------------------------------------------------
;子程序:字符栈的入栈、出栈和显示
;参数说明: (ah)=功能号,0表示入栈,1表示出栈,2表示显示
; ds:si指向字符栈空间
; 对于0号功能:(al)=入栈字符
; 对于1号功能:(al)=返回的字符
; 对于2号功能:(dh)、(dl)=字符串在屏幕上显示的行、列位置
;charstack模块开始------------------------------------------------------
charstack:
;有关charstack模块的内容,如果各位还有什么不大明白的话,
;可以查阅17.3节的内容
charstart:
push cx
push dx
push di
push es
cmp ah,2
ja sret
mov bl,ah
mov bh,0
add bx,bx
jmp word ptr table[bx]
charpush:
mov bx,top
mov [si][bx],al
inc top
jmp sret
charpop:
cmp top,0
je sret
dec top
mov bx,top
mov al,[si][bx]
jmp sret
charshow:
mov bx,0b800h
mov es,bx
mov al,160
mov ah,0
mul dh
mov di,ax
add dl,dl
mov dh,0
add di,dx
mov bx,0
charshows:
cmp bx,top
jne noempty
mov byte ptr es:[di],' '
jmp sret
noempty:
mov al,[si][bx]
mov es:[di],al
mov byte ptr es:[di+2],' '
inc bx
add di,2
jmp charshows
sret:
pop es
pop di
pop dx
pop bx
ret
getstr:
push ax
getstrs:
mov ah,0
int 16h
cmp al,20h
jb nochar
mov ah,0
call charstack
mov ah,2
call charstack
jmp getstrs
nochar:
cmp ah,0eh ;"0eh"是退格键的扫描码
je backspace
cmp ah,1ch
je enter0
jmp getstrs
backspace:
mov ah,1
call charstack
mov ah,2
call charstack
jmp getstrs
enter0:
mov al,0
mov ah,0
call charstack
mov ah,2
call charstack
pop ax
ret
;charstack模块结束------------------------------------------------------
;part2模块结束--------------------------------------------------------------------
code ends
end start | | |