ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

王爽 汇编语言第二版 课程设计2

2020-01-20 13:38:23  阅读:735  来源: 互联网

标签:课程设计 汇编语言 mov al 扇区 offset ax bx 王爽


王爽汇编语言 课程设计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 私信 关注

标签:课程设计,汇编语言,mov,al,扇区,offset,ax,bx,王爽
来源: https://blog.csdn.net/hne71/article/details/104050556

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有