!************************************************************************** !* !* Network driver interface for netboot bootrom !* !* Module: time.S !* Purpose: time related functions for DOS simulator !* Entries: dos2A, dos2B, dos2C, dos2D !* !************************************************************************** !* !* Copyright (C) 1995-2003 Gero Kuhlmann !* !* This program is free software; you can redistribute it and/or modify !* it under the terms of the GNU General Public License as published by !* the Free Software Foundation; either version 2 of the License, or !* any later version. !* !* This program is distributed in the hope that it will be useful, !* but WITHOUT ANY WARRANTY; without even the implied warranty of !* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the !* GNU General Public License for more details. !* !* You should have received a copy of the GNU General Public License !* along with this program; if not, write to the Free Software !* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. !* !* $Id: time.S,v 1.4 2003/01/25 23:29:41 gkminix Exp $ !* ! !************************************************************************** ! ! Include assembler macros: ! #include #include "dospriv.inc" ! !************************************************************************** ! ! BSS segment ! .bss .lcomm date,4 ! current date .lcomm time,4 ! current time ! !************************************************************************** ! ! Start code segment. ! .text public dos2A public dos2B public dos2C ! define entry points public dos2D ! !************************************************************************** ! ! Read current date. Note that the DOS simulator will not change the date ! over midnight. ! Input: none ! Output: AL - day of week (not used) ! CX - year ! DL - day of month ! DH - month ! Registers changed: AL, CX, DX ! dos2A: push ax push bx mov cx,word ptr [date+0] mov dx,word ptr [date+2] ! is the date already set? mov ax,cx or ax,dx jz dos2A1 mov ah,#$04 int INT_TIME ! get current date from BIOS mov al,ch call cvt2bin ! convert century number mov bl,#100 mul bl ! multiplicate by 100 xchg ax,cx xor ah,ah call cvt2bin ! convert year number add cx,ax ! add to century number mov al,dl call cvt2bin ! convert day of month mov dl,al mov al,dh call cvt2bin ! convert month mov dh,al mov word ptr [date+0],cx mov word ptr [date+2],dx ! save new date dos2A1: pop bx pop ax xor al,al ! day of week not used ret ! !************************************************************************** ! ! Set current date. This routine does not check, if a date is correct. ! Input: CX - year ! DL - day of month ! DH - month ! Output: AL - status: 00 = date is correct ! Registers changed: AL ! dos2B: mov word ptr [date+0],cx mov word ptr [date+2],dx ! save new date xor al,al ! return with success ret ! !************************************************************************** ! ! Read time. This routine uses the timer tick like the real DOS. To make ! this possible, the current time is stored on the first call to this ! routine, and then the BIOS timer tick count is reset to zero. Therefore, ! the BIOS timer count is always relative to the time stored initially. ! Input: none ! Output: CH - hour ! CL - minute ! DH - seconds ! DL - hundreds of seconds ! Registers changed: CX, DX ! dos2C: push ax mov dx,word ptr [time+0] mov cx,word ptr [time+2] mov ax,cx or ax,dx ! is this the first call? jnz dos2C1 call getcmos ! read current time call cvttime ! convert it into timer ticks mov word ptr [time+0],dx ! and save it as the reference value mov word ptr [time+2],cx xor cx,cx xor dx,dx ! reset the timer tick count to zero mov ah,#$01 int INT_TIME dos2C1: xor ah,ah int INT_TIME ! get current timer tick count add dx,word ptr [time+0] ! add it to base count adc cx,word ptr [time+2] call cvtticks ! and convert it into a time value pop ax ret ! !************************************************************************** ! ! Set time. This routine does not check whether the time is valid or not. ! If it gets an invalid time, the conversion routine might end up with ! a divide error. To set the time, a tick count will be computed and ! set as the future base value, with the BIOS timer reset to zero. ! Input: CH - hour ! CL - minutes ! DH - seconds ! DL - hundreds of seconds ! Output: AL - status: 00 = time OK ! Registers changed: AL ! dos2D: push ax push cx push dx call cvttime ! convert time into tick count mov word ptr [time+0],dx ! and save it as the base value mov word ptr [time+2],cx xor cx,cx xor dx,dx mov ah,#$01 int INT_TIME ! reset BIOS counter to zero pop dx pop cx pop ax xor al,al ! always return with success ret ! !************************************************************************** ! ! Convert time into a number of timer ticks. ! Input: CH - hour ! CL - minutes ! DH - seconds ! DL - hundreds of seconds ! Output: CX:DX - timer value ! Registers changed: AX, CX, DX ! cvttime: push bx mov al,#60 mul ch xor ch,ch ! compute number of minutes since add cx,ax ! midnight -> CX mov al,#100 mul dh ! compute number of hundred-seconds xor dh,dh ! since last minute -> DX add dx,ax xchg cx,dx mov ax,#6000 ! combine both values in CX and DX mul dx ! by first converting the number add ax,cx ! of minutes into hundred-seconds, adc dx,#0 ! and then adding both values mov cx,dx ! The BIOS generates 18.2 timer ticks per second. To convert the number ! of hundreds of seconds since midnight into the number of timer ticks, ! multiply the number by 233, and then divide by 2^8 and then by 5. mov bx,#233 mul bx ! first multiply the lower word xchg cx,ax mul bl ! then the upper byte add dx,ax ! add carry from lower to upper mov bx,#5 mov al,dh ! "divide" high word by 2^8 and move xor ah,ah ! the result into AX mov dh,dl ! "divide" low word by 2^8 and move mov dl,ch ! the result into DX div bl ! divide high word by 5 mov cl,al xor ch,ch ! CX now contains the high word of the xchg ax,dx ! end result mov dl,dh xor dh,dh div bx ! now divide the low word by 5 mov dx,ax ! put the result into CX:DX pop bx ret ! !************************************************************************** ! ! Convert number of timer ticks into time value. ! Input: CX:DX - number of timer ticks ! Output: CH - hour ! CL - minutes ! DH - seconds ! DL - hundreds of seconds ! Registers changed: AX, CX, DX ! cvtticks: push bx xchg cx,dx mov ax,cx mov bx,#65520 ! divide tick count by number of div bx ! ticks per hour mov ch,al ! save hour mov ax,dx xor dx,dx mov bx,#1092 ! divide remaining tick count by div bx ! number of ticks per minute mov cl,al ! save minute mov ax,dx mov bx,#500 mul bx ! multiply remaining tick count by mov bx,#91 ! 500 and divide by 91 to get number div bx ! of hundreds of a second xor dx,dx mov bx,#100 ! divide by 100 to get number of div bx ! seconds and number of hundreds mov dh,al pop bx ret ! !************************************************************************** ! ! Read the current time from the CMOS clock using the BIOS. ! Input: none ! Output: CH - hour ! CL - minute ! DH - seconds ! DL - hundreds of seconds ! Registers changed: AX, CX, DX ! getcmos: mov ah,#$02 int INT_TIME ! get current time from BIOS mov al,ch call cvt2bin ! convert hours mov ch,al mov al,cl call cvt2bin ! convert minutes mov cl,al mov al,dh call cvt2bin ! convert seconds mov dh,al xor dl,dl ! hundreds of seconds is always zero ret ! !************************************************************************** ! ! Routine to convert BCD value into binary value ! Input: AL - BCD value ! Output: AL - Binary value ! Registers changed: AL ! cvt2bin: push cx mov ch,al shift (shr,ch,4) ! separate upper nibble xchg ch,ah and ax,#$0F0F aad ! convert into binary mov ah,ch pop cx ret ! !************************************************************************** ! end