王爽汇编语言 课程设计2
- 掌握一门编程语言最重要的就是实践,王爽老的师的课程设计二,如果完整写出来要400行至800行代码,独立完成这个课程设计,会使你熟练16位汇编,掌握8086汇编精髓。这个课程设计不方便调试,独立完成的话要费一点时间,也许你会认为汇编已经过时了,没有必要浪费时间认真学,但是学习汇编语言,是解理计算机原理的捷径,汇编语言是万国语言的基础。如果只懂高级语言,那么只能做人家设计好东西,只能用API已经给功能,学会汇编再学编程你会感觉“道”在心中,长剑在手,有种世间任你挥撒豪情与欲望,不会再因为某种语言有没有什么功能限制你的想像与构思。学了汇编,你会知道C语言一个hello world有多么可爱,完成王爽教授的课程设计2,对于面向对象概念你会不学而解,因为敲那几百行乱七八糟的代码过程中,你会感觉你迫切迫切需要的一个东西,那就是“面向对象”。完成了课程设计2,对于指针的概念,你再也不会糊里糊涂,反面会感觉倍亲切,因为你和指针他爸是已经好朋友,和指针他妈亲密接触过,广告到此为止,再一次感谢王爽老师!
一、设计要求:
-
编写一个可以自行启动的计算机,不需要在现有操作系统环境中运行的程序
开机后, CPU 自动进入到 FFF0:0 单元处执行,此处有一条跳转指令。 CPU 执行该指令后,转去执行 BIOS 中的硬件系统检测和初始化程序。初始化程序将建立 BIOS 所支持的中断向量,即将 BIOS 提供的中断历程的入口地址登记在中断向量表中。
硬件系统检测和初始化完成后,调用 INT 19H 进行操作系统的引导。
如果设为从软盘启动操作系统,则 INT 19H 将主要完成一下工作:
( 1 )控制 0 号软驱,读取软盘 0 道 0 面 1 扇区的内容到 0 : 7C 00 。
( 2 )将 CS:IP 指向 0 : 7C 00 。
软盘的 0 道 0 面 1 扇区中装有操作系统引导程序。 INT 19H 将其装到 0 : 7C 00 处后,设置 CPU 从 0 : 7C 00 开始执行此处的引导程序,操作系统被激活,控制计算机。
如果在 0 号软驱中没有软盘,或发生软盘 I/O 错误,则 INT 19H 将主要完成以下工作 ;
(1) 读取硬盘 C 的 0 道 0 面 1 扇区的内容到 0 : 7C 00 ;
(2) 将 CS:IP 指向 0 : 7C 00 。
这次课程设计的任务是编写一个可以自行启动计算机,不需要在现有操作系统环境中运行的程序。
改程序的功能如下:
( 1 )列出功能选项,让用户通过键盘进行选择,界面如下:
1 ) reset pc ; 重新启动计算机
2 ) Start system ; 引导现有的操作系统
3 ) Clock ; 进入时钟程序
4 ) Srt clock ; 设置时间
( 2 )用户输入“ 1 ”后重新启动计算机。(提示:考虑 FFFF:0 )
( 3 )用户输入“ 2 ” 后引导现有的操作系统。(提示:考虑硬盘 C 的 0 道 0 面 1 扇区)
( 4 )用户输入“ 3 ”后,执行动态现实当前日期,时间的程序。
现实格式如下:年 / 月 / 日 时:分:秒
1、显示主菜单
2、显示并秒刷新时钟
3、设置时钟,左右箭头调整光标,esc退出,enter保存
二、实现步骤
1、写入引导区
将引导程序512字节写入A盘第1扇区,大多数电脑已经没软驱动,用vmware虚拟机来实现。
第511字节要以0aa55h结尾,这是引导标志。
写A盘引导区代码
mov ax,data
mov es,ax
mov bx,offset bootdata;es:bx内存数据。
mov dl,0;0软区
mov dh,0;0面(磁头)
mov ch,0;磁道号
mov cl,1;扇区号
mov al,1;扇区数量
mov ah,3;写扇区
int 13h
;====================================================================
引导扇区是磁盘0道0面第1扇区是512字,并且是以0aa55h结尾,上面的这些不可正好510字节,所以先写一面大小为512字并且以0aa55h结尾内存区。
data segment
bootdata db 510 dup(0)
dw 0aa55h
data ends
;===========================
;……
;===========================
mov ax,cs
mov ds,ax ;ds:si是安装源
mov si,offset boot
mov ax,data
mov es,ax
mov di,offset bootdata
mov cx,offset endboot-offset boot
cld
rep movsb
2、开机加载的引导
开机之后CPU会将导盘的0面0道第1扇区自动加载到内存的7c00h处,加载完成后,cs:ip会指向0:7c00h。
要写入0面0道第1扇区的代码
这段代码也是开机自动被加载到内存7c00h处的代。
;=========================下面是A盘1扇区内容=============================
boot:
mov ax,0
mov es,ax
mov bx,7e00h;es:bx内存数据。
mov dl,0;0软区
mov dh,0;0面(磁头)
mov ch,0;磁道号
mov cl,2;扇区号
mov al,3;扇区数量
mov ah,2;读扇区
int 13h
mov bx,offset s7e00-offset boot+7c00h
jmp dword ptr cs:[bx]
s7e00 dw 7e00h,0
endboot:nop
;====================================================================
3、引导代码boot实现的两个功能
1、把磁盘上剩余的引导代码加载到内存。
mov ax,0
mov es,ax
mov bx,7e00h;es:bx内存数据。
mov dl,0;0软区
mov dh,0;0面(磁头)
mov ch,0;磁道号
mov cl,2;扇区号
mov al,3;扇区数量
mov ah,2;读扇区
int 13h
2、把控制权交给剩余的引导代码
mov bx,offset s7e00-offset boot+7c00h
jmp dword ptr cs:[bx]
s7e00 dw 7e00h,0
三、核心代码的实现
1、设计一个循环内核
因为按设计要求要有3个界面
1)显示菜单
2)显示并刷新时钟界面
3)时钟设置界面
共有5个功能:显示菜单、重新启动、重新从C盘引导、显示时钟、设置时钟
为了实这5个功能,设计中一个单字节数字sign来标记
1)显示菜单 sign=1 esc的扫描码是1,所以用int 9h捕获到描扫码为1时,设置sign=1
2)重新启动 sign=2 键盘横排数字键1的扫描码是2,所以用int 9h捕获到描扫码为2时,设置sign=2
3)重新从C盘引导 sign=3 同上
4)显示时钟 sign=4
5)设置钟 sign=5
所以循环内核,只检测sign的值,sign=1就一直刷新显示菜单,sign=2时重启,sign=3启新引导,sign=4一直刷新显示时钟,sign=5就设置时钟。
循环代码
color db 4
functionlist dw offset endloopcore-offset do0+7e00h
dw offset showmenu -offset do0+7e00h
dw offset reset -offset do0+7e00h
dw offset startsys -offset do0+7e00h
dw offset showclock -offset do0+7e00h
dw offset setclock -offset do0+7e00h
sign db 5 ;设为0时退出,1,显示菜单,4、时显示时钟 5、设置时钟
;这几行程序一直在循环,相当于微内核================================
;sign=1时显示菜单,
;sign=2时调用reset
;sign=3时调用硬盘第一扇区
;sign=4时显示时钟
;sign=5时设置时钟
;这几行程序一直在循环,相当于微内核================================
loopcore:
mov bx,offset sign -offset sysboot+7e00h
mov bl,cs:[bx]; 取出菜单选择的数字值
mov bh,0
cmp bl,dl ; 检测选择键是否改变
je loopcore1
call clear
loopcore1:
mov dl,bl; 暂存用于下次比较
mov di,offset functionlist-offset sysboot+7e00h
add bl,bl ;functionlist 每个函数的地址是 2 字节。
add di,bx
call word ptr cs:[di]
jmp loopcore
ret
;=======================这几行程序一直在循环,相当于微内核=================
2、键盘捕获
要分三种状态捕获
1)sgin=1时,是菜单状态,捕获数字1、2、3、4键。
比如按键1时,扫描码为2,即捕获到扫描码为2时,就把设置sgin=2,键盘捕获模块只设置sign的值,不调用其他函数,int 9如果调用复杂的函数会现意外的错误。sign的值改变之后,loopcore就会调用对应的函数。
2)sgin=4时,是时钟显示状态,只捕获esc键,并设置sgin=1
3)sgin=5时,1、要捕获数0至9数字键设置时钟。2、左右箭头键调整光标位置。3、ese键退出。4、Enter保存时钟。
键盘捕获代码
color db 4
sign db 5 ;设为0时退出,1,显示菜单,4、时显示时钟 5、设置时钟
keycheck:
push ax
push bx
push dx
push di
mov bx, offset sign-offset do0+7e00h
mov ah,cs:[bx]
cmp al,3bh; F1 改变颜色
jne keyF2
mov bx, offset color-offset do0+7e00h
inc byte ptr cs:[bx]
jmp quitkeycheck
keyF2:
cmp al,3ch ; 接F2时设置sign=0,退出循环。
jne keymenu
mov byte ptr cs:[bx],0; endloopcore
jmp quitkeycheck
;================================================================
;1、只在三种状态下接收扫描码 1、sign=1 菜单状态 2、sign =4 显示clock 3、 sign=5 时置clock
;
;在菜单状态下,如果按不是1、2、3、4跳转到结束。
keymenu:
mov ah,cs:[bx]
cmp ah,1
jne keyshowclock
cmp al,2
jb quitkeycheck
cmp al,5
ja quitkeycheck
mov cs:[bx],al
jmp quitkeycheck
;===============================================================
;在显示时钟状态下只检测esc
keyshowclock:
cmp ah,4
jne keysetclock
cmp al,1
jne quitkeycheck
mov cs:[bx],al
jmp quitkeycheck
;===============================================================
;===============================================================
;设置时钟时:
;1、检测四个按键,左箭头,右箭头 ess,enter
;2、检测1,2,3,4,5,6,7,8,9,0
; 4个菜单键检测完成,跳转到结束。
keysetclock:
cmp ah,5
jne quitkeycheck
cmp al,2
jb keyleft
cmp al,0bh
ja keyleft
call settime
keyleft:
cmp al,4bh
jne keyright
call setfocus
keyright:
cmp al,4dh
jne keyesc
call setfocus
keyesc:
cmp al,1
jne keyenter
mov cs:[bx],al
keyenter:
cmp al,1ch
jne quitkeycheck
call saveclock
;=================================================================
quitkeycheck:
pop di
pop dx
pop bx
pop ax
ret
3、时钟设置
timestr db '00/00/00 00:00:00',0
timedata db 6 dup (0)
timelimitb db 0, 1, 1, 0, 0,0
timelimita db 99h,12h,31h,23h,60h,60h
timedata是6字节内存,用来保存时间数据,设置时钟的数据不直接放入timestr中,而是用时间数据最大允许值timelimita,和最小允许值timelimitb,检测一下是否是时间设置的允许值,符合要求的时间数字放入timedata中,会看到该数字被显示,不符合要求的数字不放入timedata中,就不会被显示,也不会被保存。
时间设置代码
timedata db 6 dup (0)
timeaddr db 9,8,7,4,2,0
timestr db '00/00/00 00:00:00',0
timelimitb db 0, 1, 1, 0, 0,0
timelimita db 99h,12h,31h,23h,60h,60h
focusplaces db 0,1,3,4,6,7,9,10,12,13,15,16
focus db 3
settime:
push si
push di
push ax
push bx
push cx
push dx
push bp
call scantodigit
mov bp,offset timedata -offset do0 +7e00h
mov bx,offset focus - offset do0+7e00h
;[focusplaces]= 0,1,3,4,6,7,9,10,12,13,15,16
mov bx,cs:[bx] ;取出光标索引值
mov dx,bx
and dx,1b ;如果focus单数时,取出timedata[focus/2],用键入值替换timedata[focus/2+1]
shr bx,1
add bp,bx
cmp dl,0
jne getts1
;如果focus双数时,键入值替换timedata[focus/2],取出timedata[focus/2+1]
mov dh,cs:[bp]
shl al,1
shl al,1
shl al,1
shl al,1
and dh,1111b
add al,dh
jmp gett2
getts1:
;如果focus单数时,取timedata[focus/2],用键入值替换timedata[focus/2+1]
mov dh,cs:[bp]
and dh,11110000b
add al,dh
gett2:
mov di,offset timelimitb-offset do0 +7e00h
mov si,offset timelimita-offset do0 +7e00h
mov dl,cs:[di+bx]
mov dh,cs:[si+bx]
cmp al,dl
jb quitgettime
cmp al,dh
ja quitgettime
;call bcdtochar
mov cs:[bp],al
quitgettime:
pop bp
pop dx
pop cx
pop bx
pop ax
pop di
pop si
ret
四、运行环境
操作系统:windows10
调试环境:DOSBox 0.74-3
最后的运行环境:VMware Workstation Pro15
完整的课程设计2向软盘引导区写数据,不需要任何工具的,先在Dos下运行一次即可写入软盘,再开机软驱引导即可。
在VMWare DOS直接运行即可看到演示效果。开机重启可以看到真实的引导界面。
运行步骤:
1、在VMWare的DOS环境中,编译连接运行。
2、设置软驱引导。
3、重启即可看引导界面
VMWare 设置
1、关机状态下编辑虚拟机
2、添加软驱
3、设置软驱引导
五、课程设计2的调试
1、单个模块的调试
由于课程设二是开机引导代码,在磁盘与内间把代码数据导来导去,还有一键盘中断代码,很不方便调试。
在第55行可以调试单个模块的功能。
2、演示效果调试
-
为了实现演示效,在调试时的,可以先把导代码写入A盘0面0道1扇区,剩余的引导代码写到2、3、4扇区。然再写代码模拟int 19h,把引导代码从引导扇区读到内存7c00h,然后把cs:ip指向0:7c00h如后面的代码能正常运,则可以正常开机引导。
演示代码
copyToDiskAsector:
mov ax,cs
mov ds,ax ;ds:si是安装源
mov si,offset boot
mov ax,data
mov es,ax
mov di,offset bootdata
mov cx,offset endboot-offset boot
cld
rep movsb
mov ax,data
mov es,ax
mov bx,offset bootdata;es:bx内存数据。
mov dl,0;0软区
mov dh,0;0面(磁头)
mov ch,0;磁道号
mov cl,1;扇区号
mov al,1;扇区数量
mov ah,3;写扇区
int 13h
mov ax,cs
mov es,ax
mov bx,offset sysboot;es:bx内存数据。
mov dl,0;0软区
mov dh,0;0面(磁头)
mov ch,0;磁道号
mov cl,2;扇区号
mov al,3;扇区数量
mov ah,3;写扇区
int 13h
mov ax,0
mov es,ax
mov bx,7c00h;es:bx内存数据。
mov dl,0;0软区
mov dh,0;0面(磁头)
mov ch,0;磁道号
mov cl,1;扇区号
mov al,1;扇区数量
mov ah,2;读扇区
int 13h
mov bx,offset s7c00h
jmp dword ptr ds:[bx]
s7c00h dw 7c00h,0
mov ah,4ch
int 21h
copyToDiskAsectorEnd:nop
六、关于偏移地址
1、代码段的所有offset label都是基于当前的CS,即段地是当时的CS,code segment的偏移值为0。
2、jmp label与jmp word ptr [offset label]的区别:假设label代表的地址为A,前者直接跳到label处执代码,执行结果IP=A,后者取出A处存放双字节地址B,然后跳转到B,执行效果是IP=B。call亦是如此。
mov bx,offset address -offset boot
jmp dword ptr cs:[bx]
call dword ptr cs:[bx]
address:
dw 2000h,0
;cs:[offset address -offset boot]可以准确定位到address,不怕来回复制。
;jmp 或 call可以跳到0:2000h
七、完整的代码
assume cs:code,ds:data
data segment
bootdata db 510 dup(0)
dw 0aa55h
data ends
code segment
;=======================下面是A盘2至4扇区内容===========================
;offset sysbootend-offset sysboot之间的内容是拷贝到A盘2-4扇区的内容。
;=======================下面是A盘2至4扇区内容===========================
sysboot:
jmp near ptr dostart
oldint9addr dw 0,0
;如果不加offset偏移地址会出错
menudata dw offset md0-offset sysboot+7e00h
dw offset md1-offset sysboot+7e00h
dw offset md2-offset sysboot+7e00h
dw offset md3-offset sysboot+7e00h
dw offset md4-offset sysboot+7e00h
dw offset md5-offset sysboot+7e00h
md0 db '------ welcome ------',0
md1 db '1) reset pc',0
md2 db '2) start system',0
md3 db '3) clock',0
md4 db '4) set clock',0
md5 db 'copyright @ 2020 LiuJianKun,Inc.All rights reserved.',0
timedata db 20h,2h,18h,17h,51h,0h
timeaddr db 9,8,7,4,2,0
timestr db '00/00/00 00:00:00',0
timelimitb db 0, 1, 1, 0, 0,0
timelimita db 99h,12h,31h,23h,60h,60h
focusplaces db 0,1,3,4,6,7,9,10,12,13,15,16
focus db 0
color db 4
functionlist dw offset endloopcore-offset sysboot+7e00h
dw offset showmenu -offset sysboot+7e00h
dw offset reset -offset sysboot+7e00h
dw offset startsys -offset sysboot+7e00h
dw offset showclock -offset sysboot+7e00h
dw offset setclock -offset sysboot+7e00h
sign db 5 ;设为0时退出,1,显示菜单,4、时显示时钟 5、设置时钟
stack db 128 dup (0)
dostart:
mov ax,cs;cs=0
mov ds,ax
mov ss,ax
add ax,offset dostart-offset sysboot+7e00h
mov sp,ax
call setint9 ;捕获键盘,设置9号中断,
jmp loopcore ;循环显示菜单。
;call saveclock ;调试保存时钟
;call showclock ;调试显示时钟
;================调试时钟设置================
;mov al,0ah
;call settime
;call showtimedata
;================调试时钟设置================
mov ax,4c00h
int 21h
;ret
;这几行程序一直在循环,相当于微内核================================
;sign=1时显示菜单,
;sign=2时调用reset
;sign=3时调用硬盘第一扇区
;sign=4时显示时钟
;sign=5时设置时钟
;这几行程序一直在循环,相当于微内核================================
loopcore:
mov bx,offset sign -offset sysboot+7e00h
mov bl,cs:[bx]; 取出菜单选择的数字值
mov bh,0
cmp bl,dl ; 检测选择键是否改变
je loopcore1
call clear
loopcore1:
mov dl,bl; 暂存用于下次比较
mov di,offset functionlist-offset sysboot+7e00h
add bl,bl ;functionlist 每个函数的地址是 2 字节。
add di,bx
call word ptr cs:[di]
jmp loopcore
ret
;=======================这几行程序一直在循环,相当于微内核=================
;sign=2
reset:
push bx
mov bx,offset rebootdata-offset sysboot+7c00h
jmp dword ptr cs:[bx]
rebootdata dw 0,0ffffh
pop bx
ret
;sign=3
startsys:
mov ax,0
mov es,ax
mov bx,7c00h;es:bx内存数据。
mov dl,80h;硬盘C
mov dh,0;0面(磁头)
mov ch,0;磁道号
mov cl,1;扇区号
mov al,1;扇区数量
mov ah,2;读扇区
int 13h
mov bx,offset startsys7c00h-offset sysboot+7e00h
jmp dword ptr cs:[bx]
startsys7c00h dw 7c00h,0
ret
;sign=4
showclock:
call gettimedata
call showtimedata
ret
;sign=5
setclock:
call showtimedata
ret
gettimedata:
push si
push di
push ax
mov si,offset timeaddr - offset sysboot+7e00h
mov di,offset timedata - offset sysboot+7e00h
mov cx,6
gettimedatas0:
mov al,cs:[si]
out 70h,al
in al,71h
mov cs:[di],al
inc si
inc di
loop gettimedatas0
pop ax
pop di
pop si
ret
showtimestr:
push si
push bx
mov si,offset timestr - offset sysboot+7e00h
mov bl,32;列
mov bh,13;行
call showstr
pop si
pop bx
ret
setfocus:
push ax
push bx
push dx
push si
push di
mov si,offset focus - offset sysboot+7e00h
mov bl,cs:[si]
cmp al,4bh
jne rightfocus
cmp bl,0
jne focusdec
mov bl,11
jmp showfocus
focusdec:
dec bl
jmp showfocus
rightfocus:
cmp al,4dh
jne showfocus
cmp bl,11
jne focusinc
mov bl,0
jmp showfocus
focusinc:
inc bl
jmp showfocus
showfocus:
mov cs:[si],bl;保存移动后的光标索引值
mov di,offset focusplaces - offset sysboot+7e00h
mov bh,0
mov dl,cs:[di+bx];取出光标的实际位
mov ah,2
mov bh,0
mov dh,13;行
add dl,32;列
int 10h
;setfocusquit:
pop di
pop si
pop dx
pop bx
pop ax
ret
settime:
push si
push di
push ax
push bx
push cx
push dx
push bp
call scantodigit
mov bp,offset timedata -offset sysboot +7e00h
mov bx,offset focus - offset sysboot+7e00h
mov bl,cs:[bx] ;取出光标索引值
mov bh,0
mov dx,bx
and dx,1b ;如果focus单数时,取出timedata[focus/2],用键入值对应timedata[focus/2+1]
shr bx,1
add bp,bx
cmp dl,0
jne getts1
;如果focus是双数时,键入值对应timedata[focus/2],取出timedata[focus/2+1]
mov dh,cs:[bp]
shl al,1
shl al,1
shl al,1
shl al,1
and dh,1111b
or al,dh
jmp gett2
getts1:
;如果focus是单数时,取timedata[focus/2],用键入值对应timedata[focus/2+1]
mov dh,cs:[bp]
and dh,11110000b
or al,dh
gett2:
mov di,offset timelimitb-offset sysboot +7e00h
mov si,offset timelimita-offset sysboot +7e00h
mov dl,cs:[di+bx];时钟的最小允许值
mov dh,cs:[si+bx];时钟的最大允许值
;用timedata[focus/2][focus/2+1] 与时钟最大允许值,和最小允计值比较
;判断键入的时钟最是否可用,如果可用
;则把timedata[focus/2][focus/2+1]填入timedata
cmp al,dl
jb quitgettime
cmp al,dh
ja quitgettime
;call bcdtochar
mov cs:[bp],al
quitgettime:
pop bp
pop dx
pop cx
pop bx
pop ax
pop di
pop si
ret
showtimedata:
push si
push di
push ax
push bx
push cx
mov si,offset timedata - offset sysboot+7e00h
mov di,offset timestr - offset sysboot+7e00h
mov cx,6
showclocks0:
mov al,cs:[si]
call bcdtochar
mov cs:[di+0],ah
mov cs:[di+1],al
add di,3
inc si
loop showclocks0
mov si,offset timestr - offset sysboot+7e00h
mov bl,32;列
mov bh,13;行
call showstr
showclockquit:
pop cx
pop bx
pop ax
pop di
pop si
ret
newint9:
push ax
push bx
push es
in al,60h
mov bx,0
mov es,bx
pushf
mov bx,offset oldint9addr-offset sysboot+7e00h
call dword ptr es:[bx]
call keycapture
pop es
pop bx
pop ax
iret
setint9:
push di
push ax
push es
push ds
mov ax,0
mov es,ax
mov bx,offset oldint9addr-offset sysboot+7e00h
push es:[9*4]
pop es:[bx]
push es:[9*4+2]
pop es:[bx+2]
cli
mov word ptr es:[9*4],offset newint9-offset sysboot+7e00h
mov word ptr es:[9*4+2],0
sti
pop ds
pop es
pop ax
pop di
ret
;在bh行,bl列,显si开始处的中以0结尾的字符
showstr:;9E
push es
push ax
push di
push cx
push bx
push bp
mov ax,0b800h
mov es,ax
mov al,160;每行显示80个字符,显示一个字要两字节内存1每个字符1字节,颜色1字
mul bh ;dh是行数
mov cx,bx;保存bx
mov bh,0 ;总列数保存在ax
add ax,bx;计算列数,如果用add al,bl会溢位出错
add ax,bx;计算列数,字符1字节,颜色1字节,所以加两次
mov di,ax;目标地址
mov bx,cx;恢复bx
mov bp,offset color-offset sysboot+7e00h
mov ah,cs:[bp];高字节存放颜色
mov ch,0
showstr1:
mov al,cs:[si];低字节是数据
mov es:[di],ax;高字节是颜色
inc si
add di,2
mov cl,al
jcxz showstr2
jmp showstr1
showstr2: ;D7
pop bp
pop bx
pop cx
pop di
pop ax
pop es
ret
clear:
push bx
push dx
push cx
push es
mov bx,0b800h
mov es,bx
mov bx,0
mov ds,bx
mov bx,0
mov dx,0700h ;清屏中对字符属性设置应该为07h,而不是0
mov cx,2000
clear1:
mov es:[bx],dx
add bx,2
loop clear1
pop es
pop cx
pop dx
pop bx
ret
endloopcore:
mov bx,offset sysboot-offset oldint9addr
push es:[bx]
pop es:[9*4]
push es:[bx+2]
pop es:[9*4+2]
mov ah,4ch
int 21h
ret
saveclock:
push ax
push si
push di
mov di,offset timedata -offset sysboot +7e00h
mov si,offset timeaddr -offset sysboot +7e00h
mov cx,6
saveclocks:
mov al,cs:[si]
out 70h,al
mov al,cs:[di]
out 71h,al
inc di
inc si
loop saveclocks
pop di
pop si
pop ax
ret
scantodigit:
mov ah,al
cmp al,0bh
jne gettnum1
mov al,0
jmp quitscantodigit
gettnum1:
cmp al,2
jb quitscantodigit
cmp al,0bh
ja quitscantodigit
dec al
quitscantodigit:
ret
resetfocus:
push ax
push bx
push dx
mov ah,2
mov bh,0
mov dh,25
mov dl,0
int 10h
pop dx
pop bx
pop ax
ret
;al 是bcd码,返回ah高字符,al低字符
bcdtochar:
push dx
mov dl,al
shr al,1
shr al,1
shr al,1
shr al,1
add al,30h
mov ah,al
mov al,dl
and al,1111b
add al,30h
pop dx
ret
setcolor:
push ax
push bx
mov bx,offset color-offset sysboot+7e00h
mov al,cs:[bx]
inc al
mov cs:[bx],al
pop bx
pop ax
ret
sysbootend:nop
;=======================上面是A盘2至4扇区内容===========================
;offset sysbootend-offset sysboot之间的内容是拷贝到A盘2-4扇区的内容。
;=======================上面是A盘2至4扇区内容===========================
;==========================下面是A盘1扇区内容===========================
;boot:磁盘第一扇区被加载到7c00h
;引导扇区的功能是实现把2,3,4,5扇区的
;加载到内7e00h,并把转跳到7e00h.
;=========================下面是A盘1扇区内容=============================
boot:
mov ax,0
mov es,ax
mov bx,7e00h;es:bx内存数据。
mov dl,0;0软区
mov dh,0;0面(磁头)
mov ch,0;磁道号
mov cl,2;扇区号
mov al,3;扇区数量
mov ah,2;读扇区
int 13h
mov bx,offset s7e00-offset boot+7c00h
jmp dword ptr cs:[bx]
s7e00 dw 7e00h,0
endboot:nop
;====================================================================
testRun7e00h:
mov ax,cs
mov ds,ax
mov si,offset sysboot
mov ax,0h
mov es,ax
mov di,7e00h
mov cx,offset sysbootend-offset sysboot
cld
rep movsb
mov bx,offset s7e00h-offset sysboot
jmp dword ptr cs:[bx]
s7e00h dw 7e00h,0
testRun7e00hEnd:nop
ret
copyToDiskAsector:
mov ax,cs
mov ds,ax ;ds:si是安装源
mov si,offset boot
mov ax,data
mov es,ax
mov di,offset bootdata
mov cx,offset endboot-offset boot
cld
rep movsb
mov ax,data
mov es,ax
mov bx,offset bootdata;es:bx内存数据。
mov dl,0;0软区
mov dh,0;0面(磁头)
mov ch,0;磁道号
mov cl,1;扇区号
mov al,1;扇区数量
mov ah,3;写扇区
int 13h
mov ax,cs
mov es,ax
mov bx,offset sysboot;es:bx内存数据。
mov dl,0;0软区
mov dh,0;0面(磁头)
mov ch,0;磁道号
mov cl,2;扇区号
mov al,3;扇区数量
mov ah,3;写扇区
int 13h
mov ax,0
mov es,ax
mov bx,7c00h;es:bx内存数据。
mov dl,0;0软区
mov dh,0;0面(磁头)
mov ch,0;磁道号
mov cl,1;扇区号
mov al,1;扇区数量
mov ah,2;读扇区
int 13h
mov bx,offset s7c00h
jmp dword ptr ds:[bx]
s7c00h dw 7c00h,0
mov ah,4ch
int 21h
copyToDiskAsectorEnd:nop
start:
;call copyToDiskAsector
call testRun7e00h
code ends
end start
hne71
发布了7 篇原创文章 · 获赞 0 · 访问量 2007
私信
关注