王爽汇编语言课程设计2(不涉及软盘操作,没有功能1,2)

一开始时思路错了,想着把所有按键的操作都写到 int9中断中,如果这样写会产生一系列错误,与要求也不相符。
看了看别人的思路后明白了,功能选择应该在主程序中利用 int 16中断来完成,而时钟功能中的esc返回功能和 f 1改变颜色应该借助 int 9中断来完成。

;课程设计2
;列出功能选项,让用户通过键盘进行选择,界面如下。
;(1)reset pc        重新启动计算机
;(2)start system    引导现有操作系统
;(3)clock           进入时钟程序
;(4)set clock       设置时间

assume cs:code,ds:data,ss:stack

data segment
  db '1.reset pc    '
  db '2.start system'
  db '3.clock       '
  db '4.set clock   '
data ends

stack  segment
  db 256 dup(0)
stack ends

code  segment
  begin:mov ax,stack
        mov ss,ax
	mov ax,data
	mov ds,ax

        call anint9            ;安装新的int9中断例程
    gn6:call show              ;显示主菜单
        jmp short en
	
    gn3:call day                ;功能3显示日期
  gn3_1:call day_color          ;功能3中的改变时钟颜色
        jmp short gn3

    gn4:call change_day        ;功能4改变时钟



     en:mov ah,0
        int 16h
	cmp ah,04h
	je gn3
	cmp ah,05h
	je gn4
	jmp short en


        mov ax,4c00h
	int 21h


   show:push ax                 ;显示功能函数
        push es
	push bx
	push cx
	push ds
	push di
        mov ax,0b800h
        mov es,ax
	mov bx,0
	mov cx,2000
 shows1:mov byte ptr es:[bx],' '
        add bx,2
	loop shows1
        mov bx,160*5+2*4
	mov di,0
	mov cx,4

 shows2:push cx
        mov cx,14
 shows3:mov al,[di]
        mov es:[bx],al
	inc di
	add bx,2
	loop shows3
	add bx,132
	pop cx
	loop shows2

        pop di
        pop ds
	pop cx
	pop bx
	pop es
	pop ax
	ret

        

 anint9:push ax                 ;安装新的int9中断例程
        push ds
	push cx
	push es
	push di
	push si

        mov ax,cs
        mov ds,ax
	mov ax,0
	mov es,ax
	mov si,offset int9
	mov di,204h             ;把新的int9安装到0:0204
	mov cx,offset int9end-offset int9
	cld
	rep movsb

	push es:[9*4]            ;将原int9的入口地址保存到0:0200-0204
	pop es:[200h]
	push es:[9*4+2]
	pop es:[202h]

	cli                      ;设置新的int9的中断向量表
	mov word ptr es:[9*4],204h
	mov word ptr es:[9*4+2],0
	sti
        
	pop si
	pop di
	pop es
	pop cx
	pop ds
	pop ax
	ret

   int9:
        in al,60h
	
	
	pushf                     ;调用原int9中断例程进行处理
	call dword ptr cs:[200h]

        cmp al,01h
	jne r2
        mov ax,seg gn6
        mov si,offset gn6
	jmp short retend1

     r2:cmp al,3bh
	jne retend2
	mov ax,seg gn3_1
	mov si,offset gn3_1
	jmp short retend1

        jmp short retend2
        

retend1:add sp,4
	push ax
	push si
	mov ah,0
	int 16h
	
retend2:
        iret
int9end:nop





    day:pop cx      ;实时动态日期显示
        pop cx
	mov cx,2
        mov ax,0b800h
	mov es,ax
	mov bx,0
	mov cx,2000
   days:mov byte ptr es:[bx],' '  ;显示日期前先清屏
        add bx,2
	loop days

   day0:mov bx,160*12+40*0        ;显示日期的位置
	mov dl,9
	mov cx,6
   day1:mov si,cx
        mov al,dl
	out 70h,al
	in al,71h
	mov ah,al
	mov cl,4
        shr ah,cl
	and al,00001111b

	add al,30h
	add ah,30h

	mov byte ptr es:[bx],ah
	mov byte ptr es:[bx+2],al
	mov byte ptr es:[bx+4],':'
	
	
        add bx,6       
	dec dl
	cmp bx,792h
	je  day2
	cmp bx,792h
	ja  day4
	jna day3
   day4:inc dl
   day2:sub dl,2
     
   day3:mov cx,si
        loop day1


	jmp short day0


        ret



day_color:push ax                      ;更改时间颜色
          push es
	  push bx
	  mov ax,0b800h
	  mov es,ax
	  mov bx,160*12+40*0+1
          mov cx,6
   colors:mov byte ptr es:[bx],2
          mov byte ptr es:[bx+2],2
	  add bx,6
	  loop colors
	  pop bx
	  pop es
	  pop ax
	  ret


change_day:push ax                      ;更改CMOS时间
           push es
	   push bx
	   push cx
	   push dx


           mov ax,0b800h
           mov es,ax
	   mov bx,160*10+40*0
	   mov cx,12
   changes:mov byte ptr es:[bx],'0'
           add bx,2
	   loop changes
	   mov bx,160*10+40*0
	   
       ch1:
           mov ah,0
	   int 16h
	   cmp ah,1ch
	   je ch3

	   cmp ah,0eh
	   jne ch0
	   cmp bx,640h
	   je ch2

	   dec bx
	   dec bx
	   mov byte ptr es:[bx],'0'
	   jmp short ch2
       ch0:cmp bx,658h
	   je ch2

	   cmp ah,02h
	   jb ch2
	   cmp ah,0ah
	   ja ch2
	   mov byte ptr es:[bx],al
	   add bx,2
       ch2:jmp short ch1
       ch3:
           mov cx,6
	   mov dl,9
	   mov bx,160*10+40*0
       ch4:push cx
           mov ax,es:[bx]
	   sub ah,30h
	   sub al,30h
           
	   shl al,1
	   shl al,1
	   shl al,1
	   shl al,1
	   and ah,00001111b
	   or al,ah
	   mov ah,al
	   
	   mov al,dl
	   out 70h,al
	   mov al,ah
           out 71h,al
	   add bx,4
	   
	   dec dl
	   cmp bx,160*10+6
	   je ce1
	   ja ce2
	   jna ce3

       ce2:inc dl
       ce1:sub dl,2
       ce3:pop cx
           loop ch4

	   
           pop dx
           pop cx
           pop bx
	   pop es
	   pop ax
           ret

code ends
end begin



功能选择是调用 int 16的0号功能,判断用户输入的数字在结合 cmp 和跳转指令去调用相关功能。

而时钟程序中的符 f 1功能和 esc返回主菜单功能 是靠重写int 9 中断对其输入进行处理。
在主程序中主菜单显示功能处有其调用标号,也有改变时钟颜色的调用语句及其调用处标号,
在int 9 中先判断输入,如果输入为 f 1或 esc则分别在获得主程序中调用其功能处标号的段地址和偏移地址,想要去执行他们就要改变cs 和 ip就可以了,这时就可以利用int 9 中段中的 iret返回指令,其会把栈顶的两个元素设为cs 和 ip,所以可以把栈顶的元素换成先前保存的 主程序中调用f1
功能和 esc 功能(显示主菜单)标号处的cs 和 ip。
注意:
(1)不要利用int 9 判断输入后直接call相关功能,因为这样你的int 9中段是没有执行完的,栈底会残留一开始中段过程压入的标志位寄存器和cs ip,因此多次调用int 9后会使栈发生溢出。
(2)在重写int 9的时候在每次输入的时候如果不是 f1 或 esc则键盘缓冲区会把其保存下来,所以在esc返回主菜单中继续选择功能时利用无限循环先把键盘缓冲区要清理干净,再继续判断输入的功能号
(3)因为实时显示时钟是靠循环读取cmos呈现的,所以显示时钟的子程序其ret指令是永远不会执行的,所以要在前面把call时压入栈的cs ip取出,防止多次调用其使栈发生溢出。
(4)在改变时钟颜色时注意调用完颜色改变程序后就立刻去继续执行时钟显示程序,实现实时时钟颜色改变

原文地址:https://www.cnblogs.com/revercc/p/13287096.html