实模式下时间日期的获取及显示

    技术2022-05-11  3

     

    在写一个操作系统时,时间和日期的显示功能是必不可少的,如果我们要写一个基于命令行的操作系统,通常要提供给用户两个有关时间日期的命令,即date和time。而在实模式下,可以方便地通过BIOS调用从CMOS获取当前时间及日期,然后加以处理并显示出来。BIOS中断0x1A是有关时间日期的调用,其中子功能0x02是获取当前时间,子功能0x04是获取当前日期:

    ----------------------------------------------------------- INT 1A - CLOCK - READ REAL TIME CLOCK (AT,XT286,CONV,PS) AH = 02h Return: CH = hours CL = minutes DH = seconds ----------------------------------------------------------- INT 1A - CLOCK - READ DATE FROM REAL TIME CLOCK (AT,XT286,CONV,PS) AH = 04h Return: DL = day DH = month CL = year CH = century (19 or 20) -----------------------------------------------------------

    需要注意的是,这两个BIOS调用的返回值是组合的BCD码,也就是说,在显示时我们需要先进行处理。所谓组合的BCD码,就是用二进制中的4位来表示一位十进制数,比如十进制数13,在二进制中表示为0x0D,而在组合式BCD码中表示为0x13。这样在组合式BCD码中一个字节就表示两位十进制数。

    有了这些资料,再写date和time两个命令就比较轻松了,以下是WarmOS中的代码:

    下面是显示时间的汇编代码:

    ; 字节对齐,执行效率考虑 align 4 ; 定义一个字符串 szTimeInfo db "现在的时间是:" ; 前缀 cmdTimeDH dw 0 ; 时 db ':' ; 分隔符 cmdTimeDM dw 0 ; 分 db ':' ; 分隔符 cmdTimeDS dw 0 ; 秒 db 13,10,0 ; 换行13,10及字符串结束标志0 align 4 cmdTime: mov ah,2 ; 调用BIOS中断来获取时间,24小时制 int 0x1A ; 以 12:36:24 为例 movzx ax,ch ; 小时,CH=12,用0扩展存到AX,AX=0012 ror ax,4 ; 循环右移,将AX中右4位移到左边,AX=2001,相当于把个位数移到左边 shr ah,4 ; AH=20,右移4位,AH=02,这样AH保存的就是小时的个位数了 add ax,0x3030 ; 将AX加上0x3030,其数字0的ASCII码,转换成字符,AX=0x3231 mov [cmdTimeDH],ax ; 保存到内存中,从低位到高位保存,所以内存中为0x31,0x32 ("12") movzx ax,cl ; 分钟,CL=0x36,AX=0x0036 ror ax,4 ; AX=0x6003 shr ah,4 ; AX=0x0603 add ax,0x3030 ; AX=0x3633 mov [cmdTimeDM],ax ; cmdTimeDM -> 0x33,0x36 ("36") movzx ax,dh ; 秒,DH=0x24,AX=0x0024 ror ax,4 ; AX=0x4002 shr ah,4 ; AX=0x0402 add ax,0x3030 ; AX=0x3432 mov [cmdTimeDS],ax ; cmdTimeDS -> 0x32,0x32 ("22") mov ax,0 ; WarmOS系统调用,可以换成你自己的系统的系统调用 mov bx,szTimeInfo int 0x40 ; 显示时间 ret ; 完成,返回

    下面是显示日期的代码,因为原理相似,不再详细注释,只注明寄存器值变化

    align 4 ; string define szDateInfo db "现在的日期是:" cmdDateDC dw 0 ; store year cmdDateDY dw 0 ; store year db '-' ; separator cmdDateDM dw 0 ; store month db '-' ; separator cmdDateDD dw 0 ; store day db 13,10,0 ; new line and end mark align 4 cmdDate: mov ah,4 ; BIOS function int 0x1A ; eg. 2006-07-04 movzx ax,ch ; century, CH=0x20, AX=0x0020 ror ax,4 ; AX=0x0002 shr ah,4 ; AX=0x0002 add ax,0x3030 ; AX=0x3032 mov [cmdDateDC],ax ; cmdDateDC -> 0x32,0x30 ("20") movzx ax,cl ; year, CL=0x06, AX=0x0006 ror ax,4 ; AX=0x6000 shr ah,4 ; AX=0x0600 add ax,0x3030 ; AX=0x3630 mov [cmdDateDY],ax ; cmdDateDY -> 0x30,0x36 ("06") movzx ax,dh ; month, DH=0x07, AX=0x0007 ror ax,4 ; AX=0x7000 shr ah,4 ; AX=0x0700 add ax,0x3030 ; AX=0x3730 mov [cmdDateDM],ax ; cmdDateDM -> 0x30,0x37 ("07") movzx ax,dl ; day, DL=0x04, AX=0x0004 ror ax,4 ; AX=0x4000 shr ah,4 ; AX=0x0400 add ax,0x3030 ; AX=0x3430 mov [cmdDateDD],ax ; cmdDateDD -> 0x30,0x34 ("04") mov ax,0 ; WarmOS syscall mov bx,szDateInfo int 0x40 ret ; done, return

    好了,这样就可以为系统加上两个命令了,不过这只是在实模式下,在保护模式又另当别论了。


    最新回复(0)