王爽汇编语言 课程设计2
- 掌握一门编程语言最重要的就是实践,王爽老师的课程设计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盘引导区代码
data segment
bootdata db 510 dup(0)
dw 0aa55h
data ends
;先把引导程写入512字节内存块
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
;再把512字节内存块中引导程序写入软盘引导扇区
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结尾的内存区。
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 扫描码3时,设置sign=3
4)显示时钟 sign=4 扫描码是4时,设置sign=4
5)设置钟 sign=5 扫描码是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就会调用对应的函数showclock。
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: