汇编王爽课程设计二,详细准确,符合要求

本文档详细介绍了如何在DOS环境下使用MASM5.0编译器编写程序,动态显示时间并处理INT9键盘中断。作者通过共享文件、虚拟机设置等基础知识引入,接着展示了如何解决MASM5.0编译问题,重点讲解了在INT9中断中更新时间显示和处理ESC、F1键的方法,同时讨论了引导扇区标志的必要性。程序代码包含完整注释,便于理解。
摘要由CSDN通过智能技术生成

  谢谢完成这篇代码前参阅的其它文章。没有别的老师和同学们的指导,就没有这个实验的完成。
  我用的是win10,虚拟机virtualBox,开源免费不用破解,虚拟机也可以提供3.5软驱。至于如何共享文件,如何在虚拟机里下载XP及验证码,网上都提供了很多资料,搜一搜即可。给太多链接,涉及版权,就发表不了了。
  好了,实验开始:
  我用的masm5.0在Xp系统里不很好用,编译出错后给空白行,没有提示,在外面的dosBox里就可完全根据masm5.0调试。一度卡在了引导不成功,也找不到故障在哪的境地,直到直接拿别人的好用的源代码改,只保留框架,才发现了masm5.0的问题。
  主要参考了这位大师的文章动态显示时间:所有地址标号只在代码段可用,且所有标号只记录了距离代码段开始的相对位置。脱离所在代码段,标号将不再可用,也给不出正确的结果。
  要想动态显示时间,可以延时后输出时间,但这是个死循环,唯一可以影响中断死循环的就是int 9键盘中断事件,因此,只可以在int9 中更改esc 和 F1 键的标志位,而在循环显示时间中,也不断的检测这俩键的标志位。所以,为了标号有效,就要使新 int 9 具有和主系统相同的段地址。这样,程序远转移后,esc 和 F1 的数据标号,依然有意义。有点类似于C语言的全局变量的感觉。退回主菜单时,要先恢复原 int 9
  网上也有写要在引导扇区末尾加aa55h标志的,可是课本上没有这个讲解,实验里也不用加这个,也能做出引导扇区。所以添加aa55h不是必要的。
  下面是完整代码,并带有详细注释,缩进排列。可以和链接里的那篇好文结合着看

assume cs:try2
try2 segment
main:
	mov ax,loadsys
	mov es,ax
	mov bx,0
	
	mov ah,3;write
	mov al,1;number
	mov ch,0;track
	mov cl,1;sector
	mov dh,0;face
	mov dl,0;3.5 A
	int 13h
	
	mov ax,mainsys
	mov es,ax
	mov al,15;	根据写完后的代码量,5个扇区就足够了
	mov cl,2
	mov ah,3
	int 13h
	
	mov ax,4c00h
	int 21h
try2 ends


assume cs:loadsys
loadsys segment
	mov ax,2000h
	mov es,ax
	mov bx,0;     2000:0
	
	mov ah,2;read
	mov al,15
	mov ch,0
	mov cl,2
	mov dh,0
	mov dl,0

	int 13h


	push es
	push bx
	retf
loadsys ends



assume cs:mainsys
mainsys segment
	jmp near ptr mainsys_start
	
	menu_name   dw name0,name1,name2,name3,name4,name5;menuname[bp]
	name0      db '--------welcome-------',0
	name1      db '1) restart PC',0
	name2      db '2) start winXP',0
	name3      db '3) show time',0
	name4      db '4) set time',0
	name5      db '--------welcome-------',0
	menu_choose dw menu_restart,menu_toXP,menu_show_time,menu_set_time
	
	int9_location  dw 0,0;	保存原  int 9 的入口地址
	esc_check      db 0
	time_check     db 0;验证时间的有效性,未实现,闰年呢?2月呢?
	tip_esc_F1     db 'ESC-return to menu    F1-change color',0
	tip_set_timeA	db "checking time's validity is difficult",0
	tip_set_timeB	db 'so,all your input is acceptted.',0
	tip_set_timeC	db 'Congratulations , best wishes for you ',0
	tip_set_timeD	db 'Press any key to return.....  ',0
	
	cmos_addr  db 9,8,7,4,2,0
	bcd        db 6 dup (0);		年月日时分秒
	asc        dw 6 dup (0);		年月日时分秒
	time_format db '// :: '
	
	cursor_row    db 5;	跟显示字符相关的参数
	cursor_colomn db 20;	见明知意,还少占用寄存器
	blrgb_irgb    db 02h 
	
mainsys_start:
	mov ax,cs
	mov ds,ax
	
	mov blrgb_irgb,02h;	以特定属性刷新主菜单
	call clr_screen
	
	mov cursor_row,5
	mov cursor_colomn,20
	mov cx,6
	mov bx,0
	show_mainsys_lp:
		mov si,menu_name[bx];	利用了数据标号的性质
		call show_str
		add cursor_row,2
		add bx,2
	loop show_mainsys_lp
	
	mainsys_input:
		mov ah,0
		int 16h
	
		mov bl,al
		sub bl,30h
		dec bl
		cmp bl,0
		jb mainsys_input
		cmp bl,3
		ja mainsys_input
		add bl,bl
		sub bh,bh
		call word ptr menu_choose[bx] 
	jmp mainsys_start;	跳转后附带刷新主菜单
	
	clr_screen:
		push ax
		push cx
		push es
		push di
		
		mov ax,0b800h
		mov es,ax
		mov di,0
		
		mov ah,blrgb_irgb;  黑底蓝字 + 空格
		mov al,' '
		mov cx,2000
		clrlp:
			mov es:[di],ax
			add di,2
		loop clrlp
		
		pop di
		pop es
		pop cx
		pop ax
	ret	
	
	show_str:
		push ax
		push si
		push es
		push di
		
		mov ax,0b800h
		mov es,ax
		
		mov ax,0
		mov al,160
		mul cursor_row
		mov di,ax
		mov ax,0
		mov al,cursor_colomn
		add al,al
		add di,ax;	得到显示位置
		
		mov ah,blrgb_irgb
		show_str_lp:
			cmp byte ptr ds:[si],0
			je show_str_end
			mov al,ds:[si]
			mov es:[di],ax
			add di,2
			inc si
		jmp show_str_lp
		show_str_end:
			pop di
			pop es
			pop si
			pop ax
	ret
	
	menu_restart:
		mov ax,0ffffh
		push ax
		mov ax,0	
		push ax
		retf;	修改cs:ip的巧妙语句
	
	menu_toXP:
		mov ax,0
		mov es,ax
		mov bx,7c00h
		
		mov ah,2;read
		mov al,1;num
		mov ch,0;trace
		mov cl,1;sector
		mov dh,0;face
		mov dl,80h;driver C
		int 13h
	
		push es
		push bx;	这俩寄存器可以直接入栈的
		retf
	
	menu_show_time:
		;安装新的 int 9 中断,int 9中断,终止显示时间的循环
		;不再传送,修正中断向量表,指向本系统代码段内的新 int 9
		
		mov ax,0
		mov es,ax
		push es:[9 * 4]
		pop int9_location[0] 
		push es:[9 * 4 + 2]
		pop int9_location[2]
		
		cli
		mov word ptr es:[9 * 4],offset int9_new
		mov es:[9 * 4 + 2 ],cs
		sti
		
		mov blrgb_irgb,04h
		call clr_screen
	
		mov cursor_row,5
		mov cursor_colomn,20		
		mov si,offset tip_esc_F1
		call show_str
		
		mov cursor_row,7
		show_time_lp:
			call getbcd
			call bcdtoasc
			call showasc
			
			mov dx,5
			mov cx,0
			delay:
				sub cx,1
				sbb dx,0
				cmp cx,0
				jne delay
				cmp dx,0
			jne delay
			
			cmp esc_check,1;esc 的扫描码即是1
			je show_time_end
		jmp show_time_lp
			
		show_time_end:	;恢复原 int 9,学到的最重要的处理	
			mov esc_check,0
			
			mov ax,0
			mov es,ax
			
			cli
			push int9_location[0]
			pop es:[9 * 4]
			push int9_location[2]
			pop es:[9 * 4 + 2]
			sti
	ret ;   菜单三结束
			
	getbcd:
		push ax
		push cx
		push si
		
		mov si,0
		mov cx,6
		getbcdlp:
			mov al,cmos_addr[si]
			out 70h,al
			in al,71h
			mov bcd[si],al
			inc si
		loop getbcdlp
			
		pop si
		pop cx
		pop ax
	ret		
		
	bcdtoasc:
		push ax
		push cx
		push si
			
		mov si,0
		mov cx,6
		bcdtoasclp:
			mov al,bcd[si]
			mov ah,al
			
			and al,00001111b
			add al,30h
			
			push cx
			mov cl,4
			shr ah,cl
			add ah,30h
			pop cx
			
			push si
			add si,si
			mov asc[si],ax
			pop si
				
			inc si
		loop bcdtoasclp
			
		pop si
		pop cx
		pop ax
	ret	
		
	showasc:
		push ax
		push bx
		push cx
		push si
		push es
		push di
			
		mov ax,0b800h
		mov es,ax
		
		mov ax,0
		mov al,160
		mul cursor_row
		mov di,ax
		mov ax,0
		mov al,cursor_colomn
		add al,al
		add di,ax;	得到显示位置
		
		mov si,0
		mov bh,blrgb_irgb
		mov cx,6
		shasclp:
			push si
			add si,si
			mov ax,asc[si]
			pop si
			
			mov bl,ah
			mov es:[di],bx
				
			add di,2
			mov bl,al
			mov es:[di],bx
				
			add di,2
			mov bl,time_format[si]			
			mov es:[di],bx
			
			add di,2
			inc si
		loop shasclp
			
		pop di
		pop es
		pop si
		pop cx
		pop bx
		pop ax
	ret		
		
	int9_new:
		push ax
		push si
		
		pushf
		pushf
		pop ax
		and ah,11111100b
		push ax
		popf
;		call far ptr int9_location  ???这么做不对,下面就对  跟课本不一致

		mov si,offset int9_location
		call dword ptr ds:[si]
		
		in al,60h
		cmp al,1;	1--esc
		je esc_clicked
		cmp al,3bh;	3bh--F1
		je F1_clicked
	
		int9_new_end: 	 
			pop si
			pop ax
	iret
		esc_clicked:     
			mov esc_check,al
			jmp int9_new_end
		F1_clicked:     
			inc blrgb_irgb
			mov ah,0
			int 16h	;可见在int 9 中仍可以调用中断
			jmp int9_new_end
	
	menu_set_time: 
		mov blrgb_irgb,3dh
		call clr_screen
	
		mov cursor_row,5
		mov cursor_colomn,10		
		mov si,offset tip_set_timeA
		call show_str
		
		mov cursor_row,6
		mov cursor_colomn,10		
		mov si,offset tip_set_timeB
		call show_str		
	
		mov cursor_row,10
		mov cursor_colomn,15
		call getbcd
		call bcdtoasc
		call showasc
		call newtime
		call savasc
		call asctobcd
		call setcmos
		
		mov cursor_row,15
		mov cursor_colomn,10		
		mov si,offset tip_set_timeC
		call show_str	
		
		mov cursor_row,17
		mov cursor_colomn,10		
		mov si,offset tip_set_timeD
		call show_str	
		
		mov ah,0;	实现延时
		int 16h
	
	ret 

	newtime:			;按enter键完成输入,支持箭头<---->选择时间
		push ax			;并能跳过时间格式字符,准确落在数字上
		push es			;移动到两边时,并不会越界,
		push di			;能够使待修改字符闪烁,提醒修改位置
		push bp
		
		mov ax,0b800h
		mov es,ax
		
		mov ax,0
		mov al,160
		mul cursor_row
		mov di,ax
		mov ax,0
		mov al,cursor_colomn
		add al,al
		add di,ax;	得到显示位置
		
		mov bp,0;	es:[di+bp]
		newtimelp:
			or byte ptr es:[di+bp+1],10000000b;	实现待修改字符的闪烁
			
			mov ah,0
			int 16h
			
			cmp ah,4bh;	<--  通码4bH
			je toleft
			cmp ah,4dh;	-->  通码4dh
			je toright
			cmp ah,1ch;		enter 通码 1ch
			je timeover
			
			cmp ah,2h;	1~9,0  范围是 2~Bh
			jb newtimelp
			cmp ah,0bh
			ja newtimelp
			mov es:[di+bp],al
			jmp toright
			
			toleft:
				cmp bp,0
				jna newtimelp			  ; 空格20h
				cmp byte ptr es:[di+bp-2],'0';/29h < 数字 < :3ah
				jb leftone
				cmp byte ptr es:[di+bp-2],'9'
				ja leftone
				and byte ptr es:[di+bp+1],01111111b
				sub bp,2		
				jmp newtimelp
				leftone:
					and byte ptr es:[di+bp+1],01111111b
					sub bp,4
					jmp newtimelp	
			
			toright:
				cmp bp,32;	秒的最后一位
				jnb newtimelp
				cmp byte ptr es:[di+bp+2],'0'
				jb rightone
				cmp byte ptr es:[di+bp+2],'9'
				ja rightone
				and byte ptr es:[di+bp+1],01111111b
				add bp,2
				jmp newtimelp
				rightone:
					and byte ptr es:[di+bp+1],01111111b
					add bp,4
					jmp newtimelp
			
		timeover:
			and byte ptr es:[di+bp+1],01111111b
			pop bp
			pop di
			pop es
			pop ax
	ret	

	savasc:
		push ax
		push cx
		push si
		push es
		push di
		
		mov ax,0b800h
		mov es,ax
		
		mov ax,0
		mov al,160
		mul cursor_row
		mov di,ax
		mov ax,0
		mov al,cursor_colomn
		add al,al
		add di,ax;	得到显示位置

		mov si,offset asc
		mov cx,6
		savasclp:
			mov ah,es:[di]
			mov al,es:[di+2]
			mov ds:[si],ax
			add si,2
			add bp,6
		loop savasclp
		
		pop di
		pop es
		pop si
		pop cx
		pop ax
	ret

	asctobcd:
		push ax
		push cx
		push si
		
		mov si,0
		mov cx,6
		asctobcdlp:
			push si
			add si,si
			mov ax,asc[si]
			pop si
			
			sub ah,30h
			push cx
			mov cl,4
			shl ah,cl
			pop cx
			sub al,30h
			or al,ah
			mov bcd[si],al
			
			inc si
		loop asctobcdlp
		
		pop si
		pop cx
		pop ax
	ret
			
	setcmos:
		push ax
		push cx
		push si
		
		mov si,0
		mov cx,6
		setcmoslp:
			mov al,cmos_addr[si]
			out 70h,al
			mov al,bcd[si]
			out 71h,al
			
			inc si
		loop setcmoslp
		
		pop si
		pop cx
		pop ax
	ret	
	
mainsys ends
end main 

下面是演示效果:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
谢谢阅读。并向网络上分享知识的您们致以深深的谢意。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
阅读下面的材料 : 开机后, 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 ”后,执行动态现实当前日期,时间的程序。 现实格式如下:年 / 月 / 日 时:分:秒 进入此项功能后,一直动态现实当前的时间,在屏幕上将出现时间按秒变化的效果。(提示:循环读取 CMOS ) 当按下 F1 键后,改变现实颜色;按下 ESC 键后,返回到主选单。(提示:利用键盘中断) ( 5 )用户输入“ 4 ”后可更改当前的日期,时间,更改后返回到主选单。(提示:输入字符串) 下面给出的几点建议: ( 1 )在 DOS 下编写安装程序,在按转程序中包含任务程序; ( 2 )运行安装程序,将任务程序写到软盘上; ( 3 )若要任务程序可以在开机后自行执行,要将它写到软盘的 0 道 0 面 1 扇区上。如果程序长度大于 512B ,则需要用多个扇区存放,这种情况下,处于软盘 0 道 0 面 1 扇区中的程序就必须负责将其他扇区中的内容读入内存。 这个程序较为复杂,它用到了我们所学到的所有技术,需要进行仔细地分析和耐心地调试。这个程序对于我们的整个学习过程是具有总结性的,希望读者能够尽力完成。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值