; ============================================================================= ; ; Litos8 date and time ; ; ============================================================================= ; ----------------------------------------------------------------------------- ; Exported user functions (47): ; PackBCDByte - pack 1 byte to BCD format ; PackBCD2Byte - pack 2 bytes to BCD format ; PackBCD4Byte - pack 4 bytes to BCD format ; UnpackBCDByte - unpack 1 byte from BCD format ; UnpackBCD2Byte - unpack 2 bytes from BCD format ; UnpackBCD4Byte - unpack 4 bytes from BCD format ; ReadDT - read registers from DATETIME structure ; WriteDT - write registers to DATETIME structure ; PackDOSDate - pack date do DOS file format ; UnpackDOSDate - unpack date from DOS file format ; PackDOSTime - pack time to DOS file format ; UnpackDOSTime - unpack time from DOS file format ; DateValidate - limit date to valid values ; TimeValidate - limit time to valid values ; DateTimeValidate - limit date and time to valid values ; DateTimeValidateDT - limit date and time to valid values with DATETIME ; ClockValidate - limit clock timer value ; PackUnixTime - pack date and time to Unix format ; UnpackUnixTime - unpack date and time from Unix format ; DayToUnix - convert days to Unix format ; UnixToDay - covert Unix format to days ; GetTime - get current time ; GetDate - get current date ; GetDateTime - get current date and time ; GetDateTimeDT - get current date and time with DATETIME structure ; GetTimeUnix - get current time in Unix format ; GetDateUnix - get current date in Unix format ; GetDateTimeUnix - get current date and time in Unix format ; Clock2Unix - convert clock timer to Unix time ; Clock2Time - convert clock timer to time ; Time2Clock - convert time to clock timer ; GetClockTimer - get clock timer ; SetClockTimer - set clock timer ; GetRTCTime - get time from RTC (CMOS) clock ; GetRTCDate - get date from RTC (CMOS) clock ; GetRTCDateTime - get date and time from RTC (CMOS) clock ; GetRTCDateTimeDT - get date and time from RTC clock with DATETIME ; SetTime - set new time ; SetDate - set new date ; SetDateTime - set new date and time ; SetDateTimeDT - set new date and time with DATETIME ; ReinitDateTime - reinitialize date and time from RTC (CMOS) clock ; GetSysTimer - get system timer ; SysTimerToUs - recalc system timer interval to microseconds ; UsToSysTimer - recalc microseconds to system timer interval ; WaitUs - wait short time in microseconds ; WaitMs - wait given time in milliseconds ; ----------------------------------------------------------------------------- ; PC Real-time clock (clock timer, counter 0): ; Crystal oscilator generates 14.31818 MHz, which is divided by 12. ; Hardware clock generator: 1.193180 MHz (correct value is 1.193181667MHz) ; Timer divisor: 65536 ; Interrupt frequency: 18.20648193 Hz (correct value 18.206507365 Hz) ; Interrupt interval: 54.92549322 ms (correct value 54.925416498 ms) ; Ticks per day: 1573040, 1800B0h (correct value 1573042, 1800B2h) ; Hundredths second per day: 8640000 ; Recalc counter to hundredth second: 100*65536/1193180 = 5*65536/59659 CODEINIT_SECTION ; ----------------------------------------------------------------------------- ; INIT: Initialize date and time service ; ----------------------------------------------------------------------------- ; ------------- get clock timer to update date -> DX:AX InitDateTime: call GetClockTimer ; get clock timer ; ------------- get date and time from RTC (CMOS) clock call GetRTCDateTime ; get date and time from RTC clock mov bl,0 ; BL <- 0, hundredth ; ------------- set date call PackUnixTime ; pack date to Unix format call UnixToDay ; conver Unix format to day mov [Date],ax ; store current date ret CODE_SECTION ; ----------------------------------------------------------------------------- ; Reinitialize date and time from RTC (CMOS) clock ; ----------------------------------------------------------------------------- ; NOTES: Can be used after changing TIMER0 (Int 08h) frequency. ; ----------------------------------------------------------------------------- ; ------------- Push registers ReinitDateTime: push ax ; push AX push bx ; push BX push cx ; push CX push dx ; push DX push si ; push SI ; ------------- get date and time from RTC (CMOS) clock call GetRTCDateTime ; get date and time from RTC clock mov bl,0 ; BL <- 0, hundredth ; ------------- set clock timer push dx ; push DX call Time2Clock ; convert time to clock timer call SetClockTimer ; set clock timer pop dx ; pop DX ; ------------- set date call PackUnixTime ; pack date to Unix format call UnixToDay ; conver Unix format to day mov [Date],ax ; store current date ; ------------- pop registers pop si ; pop SI pop dx ; pop DX pop cx ; pop CX pop bx ; pop BX pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; Pack 4 bytes to BCD format ; ----------------------------------------------------------------------------- ; INPUT: DH,DL,AH,AL = binary numbers (0..99) ; OUTPUT: DH,DL,AH,AL = BCD numbers (00h..99h) ; ----------------------------------------------------------------------------- PackBCD4Byte: xchg ax,dx ; DH,DL <- high BIN, AH,AL <- low BIN call PackBCD2Byte ; pack bytes in AH,AL to BCD format xchg ax,dx ; DH,DL <- low BIN, AH,AL <- high BCD ; === PackBCD2Byte function must follow! ; ----------------------------------------------------------------------------- ; Pack 2 bytes to BCD format ; ----------------------------------------------------------------------------- ; INPUT: AH,AL = binary numbers (0..99) ; OUTPUT: AH,AL = BCD numbers (00h..99h) ; ----------------------------------------------------------------------------- PackBCD2Byte: xchg al,ah ; AL <- high BIN, AH <- low BIN call PackBCDByte ; pack byte in AL to BCD format xchg al,ah ; AL <- low BIN, AH <- high BCD ; === PackBCDByte function must follow! ; ----------------------------------------------------------------------------- ; Pack 1 byte to BCD format ; ----------------------------------------------------------------------------- ; INPUT: AL = binary number (0..99) ; OUTPUT: AL = BCD number (00h..99h) ; ----------------------------------------------------------------------------- ; ------------- push registers PackBCDByte: push cx ; push CX mov cx,ax ; CH <- push registers AH ; ------------- pack number in AL aam ; AH <- tens, AL <- ones mov cl,4 ; CL <- number of rotations shl ah,cl ; AH << 4 or al,ah ; AL <- BCD number ; ------------- pop registers mov ah,ch ; pop register AH pop cx ; pop CX ret ; ----------------------------------------------------------------------------- ; Unpack 4 bytes from BCD format ; ----------------------------------------------------------------------------- ; INPUT: DH,DL,AH,AL = BCD numbers (00h..99h) ; OUTPUT: DH,DL,AH,AL = binary numbers (0..99) ; ----------------------------------------------------------------------------- UnpackBCD4Byte: xchg ax,dx ; DH,DL <- high BCD, AH,AL <- low BCD call UnpackBCD2Byte ; unpack bytes in AH,AL from BCD format xchg ax,dx ; DH,DL <- low BCD, AH,AL <- high BIN ; === UnpackBCD2Byte function must follow! ; ----------------------------------------------------------------------------- ; Unpack 2 bytes from BCD format ; ----------------------------------------------------------------------------- ; INPUT: AH,AL = BCD numbers (00h..99h) ; OUTPUT: AH,AL = binary numbers (0..99) ; ----------------------------------------------------------------------------- UnpackBCD2Byte: xchg al,ah ; AL <- high BCD, AH <- low BCD call UnpackBCDByte ; unpack byte in AL from BCD format xchg al,ah ; AL <- low BCD, AH <- high BIN ; === UnpackBCDByte function must follow! ; ----------------------------------------------------------------------------- ; Unpack 1 byte from BCD format ; ----------------------------------------------------------------------------- ; INPUT: AL = BCD number (00h..99h) ; OUTPUT: AL = binary number (0..99) ; ----------------------------------------------------------------------------- ; ------------- push registers UnpackBCDByte: push cx ; push CX mov cx,ax ; CH <- push registers AH ; ------------- unack number in AL mov cl,4 ; CL <- number of rotations mov ah,al ; AH <- number to unpack shr ah,cl ; AH <- BCD digit HIGH and al,0fh ; AL <- BCD digit LOW aad ; AL <- 10*AH + AL ; ------------- pop registers mov ah,ch ; pop register AH pop cx ; pop CX ret ; ----------------------------------------------------------------------------- ; read registers from DATETIME structure ; ----------------------------------------------------------------------------- ; INPUT: DI = pointer to DATETIME structure ; OUTPUT: BL = hundredth (0..99) ; BH = second (0..59) ; CL = minute (0..59) ; CH = hour (0..23) ; DL = day (1..31) ; DH = month (1..12) ; SI = year (1970..2106) ; ----------------------------------------------------------------------------- ReadDT: mov bx,[di+DATETIME_Hundr] ; BL <- hundredth, BH <- second mov cx,[di+DATETIME_Min] ; CL <- minute, CH <- hour mov dx,[di+DATETIME_Day] ; DL <- day, DH <- month mov si,[di+DATETIME_Year] ; SI <- year ret ; ----------------------------------------------------------------------------- ; write registers to DATETIME structure ; ----------------------------------------------------------------------------- ; INPUT: DI = pointer to DATETIME structure ; BL = hundredth (0..99) ; BH = second (0..59) ; CL = minute (0..59) ; CH = hour (0..23) ; DL = day (1..31) ; DH = month (1..12) ; SI = year (1970..2106) ; ----------------------------------------------------------------------------- WriteDT: mov [di+DATETIME_Hundr],bx ; write hundredth and second mov [di+DATETIME_Min],cx ; write minute and hour mov [di+DATETIME_Day],dx ; write day and month mov [di+DATETIME_Year],si ; write year ret ; ----------------------------------------------------------------------------- ; Pack date to DOS file format ; ----------------------------------------------------------------------------- ; INPUT: DL = day (1..31, can be 0..31) ; DH = month (1..12, can be 0..15) ; SI = year (1980..2117) ; OUTPUT: AX = date in DOS file format ; bit 0..4: day (1..31, can be 0..31) ; bit 5..8: month (1..12, can be 0..15) ; bit 9..15: year - 1980 (0..127 = 1980..2117) ; ----------------------------------------------------------------------------- ; ------------- push registers PackDOSDate: push cx ; push CX ; ------------- pack year -> CH mov cx,si ; CX <- year sub cx,1980 ; CX <- offset from 1980 shl cx,1 ; CL <- year - 1980 mov ch,cl ; CH <- year - 1980 ; ------------- pack month mov al,dh ; AL <- month cbw ; AX <- month mov cl,5 ; CL <- 5 number of rotations shl ax,cl ; shift month to bit 5 ; ------------- add year and day or ah,ch ; AH <- add year or al,dl ; add day ; ------------- pop registers pop cx ; pop CX ret ; ----------------------------------------------------------------------------- ; Unpack date from DOS file format ; ----------------------------------------------------------------------------- ; INPUT: AX = date in DOS file format ; bit 0..4: day (1..31, can be 0..31) ; bit 5..8: month (1..12, can be 0..15) ; bit 9..15: year - 1980 (0..127 = 1980..2117) ; OUTPUT: DL = day (1..31, can be 0..31) ; DH = month (1..12, can be 0..15) ; SI = year (1980..2117) ; ----------------------------------------------------------------------------- ; ------------- push registers UnpackDOSDate: push ax ; push AX push cx ; push CX ; ------------- unpack day -> DL and month -> DH mov dx,ax ; DX <- date mov cl,3 ; CL <- rotations to shift B5 -> B8 shl dx,cl ; DH <- month, DL <- day << 3 and dh,0fh ; DH <- month shr dl,cl ; DL <- day ; ------------- unpack year -> CX mov cl,9 ; CL <- rotations for year shr ax,cl ; AX <- year offset add ax,1980 ; add base xchg ax,si ; SI <- year ; ------------- pop registers pop cx ; pop CX pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; Pack time to DOS file format ; ----------------------------------------------------------------------------- ; INPUT: BH = second (0..58, can be 0..62, converted to even second) ; CL = minute (0..59, can be 0..63) ; CH = hour (0..23, can be 0..31) ; OUTPUT: AX = time in DOS file format ; bit 0..4: second/2 (value 0..29 = 0..58 seconds, ; can be 0..31 = 0..62 seconds) ; bit 5..10: minute (0..59, can be 0..63) ; bit 11..15: hour (0..23, can be 0..31) ; ----------------------------------------------------------------------------- ; ------------- push registers PackDOSTime: push cx ; push CX ; ------------- pack minute -> AX mov al,cl ; AL <- minute cbw ; AX <- minute mov cl,5 ; CL <- number of rotations shl ax,cl ; AX <- shift minute to position ; ------------- pack hour -> AH mov cl,11-8 ; CL <- number of rotations shl ch,cl ; CH <- hour in right position or ah,ch ; AH <- add hour ; ------------- add second -> AL mov ch,bh ; CH <- second shr ch,1 ; CH <- second / 2 or al,ch ; AL <- add second ; ------------- pop registers pop cx ; pop CX ret ; ----------------------------------------------------------------------------- ; Unpack time from DOS file format ; ----------------------------------------------------------------------------- ; INPUT: AX = time in DOS file format ; bit 0..4: second/2 (value 0..29 = 0..58 seconds, ; can be 0..31 = 0..62 seconds) ; bit 5..10: minute (0..59, can be 0..63) ; bit 11..15: hour (0..23, can be 0..31) ; OUTPUT: BH = second (0..58, can be 0..62, only even second) ; CL = minute (0..59, can be 0..63) ; CH = hour (0..23, can be 0..31) ; ----------------------------------------------------------------------------- ; ------------- push registers UnpackDOSTime: push ax ; push AX ; ------------- unpack second -> BH mov bh,al ; BH <- time LOW and bh,1fh ; BH <- second / 2 shl bh,1 ; BH <- second ; ------------- unpack hour -> CH and minute -> CL mov cl,3 ; CL <- rotations to shift hour shr ax,cl ; AH <- hour, AL <- minute << 2 mov cl,2 ; CL <- rotations to shift minute shr al,cl ; AL <- minute xchg ax,cx ; CH <- hour, CL <- minute ; ------------- pop registers pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; INTERNAL: Convert year to days ; ----------------------------------------------------------------------------- ; INPUT: CX = year - 1970 (value 0..136 = year 1970..2106) ; OUTPUT: AX = days ; DESTROYS: DX ; ----------------------------------------------------------------------------- ; days = year*365 + (year+1)/4; if (year > 130) days -= 1 YearToDays: mov ax,365 ; AX <- number of days per year mul cx ; AX <- days (result 0..49640) mov dx,cx ; DX <- year inc dx ; DX += 1 shr dx,1 ; DX <- (year+1)/2 shr dx,1 ; DX <- (year+1)/4 add ax,dx ; AX <- add leap years (0..49674) cmp cl,130 ; year > 2100 ? jbe short YearToDays2 ; year <= 2100 dec ax ; leap correction YearToDays2: ret ; ----------------------------------------------------------------------------- ; Limit date to valid values ; ----------------------------------------------------------------------------- ; INPUT: DL = day (1..31) ; DH = month (1..12) ; SI = year (1970..2106) ; OUTPUT: values can be corrected to valid range ; ----------------------------------------------------------------------------- ; ------------- push registers DateValidate: push bx ; push BX ; ------------- validate month cmp dh,1 ; minimal value ja short DateValidate2 ; value is OK mov dh,1 ; DH <- limit to minimal value DateValidate2: cmp dh,12 ; maximal value jb short DateValidate3 ; valule is OK mov dh,12 ; DH <- limit to maximal value ; ------------- validate year DateValidate3: cmp si,1970 ; minimal value ja short DateValidate4 ; year is OK mov si,1970 ; SI <- limit to minimal value DateValidate4: cmp si,2106 ; maximal value jb short DateValidate5 ; value is OK mov si,2106 ; SI <- limit to maximal value ; ------------- limit year 2106 to 2/7/2106 (6:28:15) cmp dh,2 ; maximal month jb short DateValidate5 ; value is OK mov dh,2 ; DH <- limit to maximal value cmp dl,7 ; maximal day jb short DateValidate5 ; value is OK mov dl,7 ; DL <- limit to maximal value ; ------------- validate day DateValidate5: cmp dl,1 ; minimal value ja short DateValidate6 ; value is OK mov dl,1 ; DL <- limit to minimal value DateValidate6: mov bl,dh ; BL <- month dec bx ; BX <- correction - 1 mov bh,0 ; BX <- month - 1 add bx,DaysInMonth ; BX <- table of days test si,3 ; leap year? jnz short DateValidate7 ; not leap year cmp si,2100 ; year 2100 ? je short DateValidate7 ; not leap year add bx,DaysInMonthL-DaysInMonth ; leap year DateValidate7: cmp dl,[bx] ; check day jbe short DateValidate8 ; day is OK mov dl,[bx] ; DL <- limit day ; ------------- pop registers DateValidate8: pop bx ; pop BX ret ; ----------------------------------------------------------------------------- ; Limit time to valid values ; ----------------------------------------------------------------------------- ; INPUT: BL = hundredth (0..99) ; BH = second (0..59) ; CL = minute (0..59) ; CH = hour (0..23) ; OUTPUT: values can be corrected to valid range ; ----------------------------------------------------------------------------- ; ------------- validate hundredth TimeValidate: or bl,bl ; negative? jns short TimeValidate2 ; not negative mov bl,0 ; BL <- limit to minimal value TimeValidate2: cmp bl,99 ; maximal value jb short TimeValidate3 ; value is OK mov bl,99 ; BL <- limit to maximal value ; ------------- validate second TimeValidate3: or bh,bh ; negative? jns short TimeValidate4 ; not negative mov bh,0 ; BH <- limit to minimal value TimeValidate4: cmp bh,59 ; maximal value jb short TimeValidate5 ; value is OK mov bh,59 ; BH <- limit to maximal value ; ------------- validate minute TimeValidate5: or cl,cl ; negative? jns short TimeValidate6 ; not negative mov cl,0 ; CL <- limit to minimal value TimeValidate6: cmp cl,59 ; maximal value jb short TimeValidate7 ; value is OK mov cl,59 ; CL <- limit to maximal value ; ------------- validate hour TimeValidate7: or ch,ch ; negative? jns short TimeValidate8 ; not negative mov ch,0 ; CH <- limit to minimal value TimeValidate8: cmp ch,23 ; maximal value jb short TimeValidate9 ; value is OK mov ch,23 ; CH <- limit to maximal value TimeValidate9: ret ; ----------------------------------------------------------------------------- ; Limit date and time to valid values ; ----------------------------------------------------------------------------- ; INPUT: BL = hundredth (0..99) ; BH = second (0..59) ; CL = minute (0..59) ; CH = hour (0..23) ; DL = day (1..31) ; DH = month (1..12) ; SI = year (1970..2106) ; OUTPUT: values can be corrected to valid range ; ----------------------------------------------------------------------------- ; ------------- date and time validate DateTimeValidate: call DateValidate ; date validate call TimeValidate ; time validate ; ------------- limit to 2/7/2106 6:28:15 cmp si,2106 ; maximal year 2106 jne short DateTimeValid4 ; not 2106 cmp dx,207h ; maximal month and day 2/7/2106 jne short DateTimeValid4 ; not 2/7/2106 cmp ch,6 ; maximal hour jb short DateTimeValid4 ; value is OK mov ch,6 ; CH <- limit to maximal value cmp cl,28 ; maximal minute jb short DateTimeValid4 ; value is OK mov cl,28 ; CL <- limit to maximal value cmp bh,15 ; maximal second jb short DateTimeValid4 ; value is OK mov bh,15 ; BH <- limit to maximal value DateTimeValid4: ret ; ----------------------------------------------------------------------------- ; Limit date and time to valid values with DATETIME structure ; ----------------------------------------------------------------------------- ; INPUT: DI = pointer to DATETIME structure ; OUTPUT: values in DATETIME can be corrected to valid range ; ----------------------------------------------------------------------------- ; ------------- push registers DateTimeValidateDT: push bx ; push BX push cx ; push CX push dx ; push DX push si ; push SI ;-------------- limit values call ReadDT ; read registers from DATETIME call DateTimeValidate ; limit date and time call WriteDT ; write registers to DATETIME ; ------------- pop registers pop si ; pop SI pop dx ; pop DX pop cx ; pop CX pop bx ; pop BX ret ; ----------------------------------------------------------------------------- ; Limit clock timer value ; ----------------------------------------------------------------------------- ; INPUT: DX:AX = clock timer (0..1800AFh, interval 54.92549322ms) ; OUTPUT: value can be corrected to valid range ; ----------------------------------------------------------------------------- ClockValidate: cmp dx,18h ; maximal value HIGH jb short ClockValidate2 ; value is OK mov dx,18h ; DX <- limit to maximal value cmp ax,0afh ; maximal value LOW jb short ClockValidate2 ; value is OK mov ax,0afh ; AX <- limit to maximal value ClockValidate2: ret ; ----------------------------------------------------------------------------- ; Pack date and time to Unix format ; ----------------------------------------------------------------------------- ; INPUT: BH = second (0..59) ; CL = minute (0..59) ; CH = hour (0..23) ; DL = day (1..31) ; DH = month (1..12) ; SI = year (1970..2106) ; OUTPUT: DX:AX = number of seconds since 1/1/1970 0:00:00 Thursday ; NOTES: Maxim date/time: 2/7/2106 6:28:15 (result 0ffffh:0ffffh) ; ----------------------------------------------------------------------------- ; Julian date 1/1/1970:2440587, 2/7/2106:2490297, difference 49710, 4294944000s ; leap years (februar is 29): 1972, 1976, 1980, 1984, 1988... but not 2100 ; ------------- push registers PackUnixTime: push bx ; push BX push cx ; push CX push si ; push SI push di ; push DI ; ------------- limit date and time values call DateTimeValidate ; limit date and time values ; ------------- prepare year -> CX (0..136) ; BH = second, CL = minute, CH = hour, DL = day, DH = month, SI = year ; year = year - 1970 mov al,bh ; AL <- second mov bx,cx ; BL <- minute, BH <- hour mov cx,si ; CX <- year sub cx,1970 ; CX <- offset from 1970 (0..136) ; ------------- convert time to seconds -> DI:SI (0..86399) ; AL = second, BL = minute, BH = hour, CX = year, DL = day, DH = month ; time = (hour*60 + minute)*60 + second push dx ; push DX, day and month cbw ; AX <- second xchg ax,si ; SI <- second mov al,60 ; AL <- number of minutes per hour mul bh ; AX <- recalc hour to minutes mov bh,0 ; BX = minute add ax,bx ; AX <- add minute (result 0..1439) mov dx,60 ; DX <- number of seconds per minute mul dx ; DX:AX <- recalc minutes to seconds add si,ax ; add seconds (result 0..86399) adc dx,byte 0 ; DX:SI <- seconds from time mov di,dx ; DI <- time in seconds HIGH ; ------------- convert year to days -> AX (0..49674) ; CX = year, DI:SI = time in seconds, [sp] = day+month ; days = year*365 + (year+1)/4; if (year > 130) days -= 1 call YearToDays ; convert year CX to days->AX, destr.DX pop dx ; pop DX, day and month ; ------------- add days in month from start of year -> AX (0..50008) ; AX = year in days, CX = year, DL = day, DH = month, DI:SI = time in seconds ; days = days + DaysInYear[month-1] mov bl,dh ; BL <- month mov bh,0 ; BX <- month shl bx,1 ; BX <- offset in table add ax,[bx+DaysInYear-2]; AX <- add days from start of year ; ------------- februar correction -> AX ; AX=year+month in days, CX=year, DL=day, DH=month, DI:SI=time in seconds ; if ((month > 2) && (year != 130) && (((year+2) & 3) == 0) days++ cmp dh,2 ; februar? jbe short PackUnixTime4 ; no correction cmp cx,130 ; year 2100 ? je short PackUnixTime4 ; year 2100 inc cx ; DI <- year + 1 inc cx ; DI <- year + 2 test cl,3 ; overlapped year? jnz short PackUnixTime4 ; not overlapped year inc ax ; correction for februar ; ------------- add day in month -> AX (0..50038) ; AX=year+month in days, CX=year, DL=day, DH=month, DI:SI=time in seconds ; days = days + day - 1 PackUnixTime4: mov dh,0 ; DX = day dec dx ; DX <- day 0..30 add ax,dx ; AX <- add days in month ; ------------- convert days to seconds -> DX:AX ; AX=date in days, CX=year, DI:SI=time in seconds ; time = (days * (24*60*60/2)) * 2 mov dx,24*60*60/2 ; DX <- seconds per day / 2 (43200) mul dx ; DX:AX <- convert days to second/2 shl ax,1 ; AX *= 2 rcl dx,1 ; DX:AX <- days converted to seconds ; ------------- add time -> DX:AX ; DX:AX = date in seconds, DI:SI = time in seconds add ax,si ; AX <- add time LOW adc dx,di ; DX <- add time HIGH ; ------------- pop registers pop di ; pop DI pop si ; pop SI pop cx ; pop CX pop bx ; pop BX ret ; ----------------------------------------------------------------------------- ; Unpack date and time from Unix format ; ----------------------------------------------------------------------------- ; INPUT: DX:AX = number of seconds since 1/1/1970 0:00:00 Thursday ; OUTPUT: AL = day of week (1..7, 1=Monday...7=Sunday) ; BH = second (0..59) ; CL = minute (0..59) ; CH = hour (0..23) ; DL = day (1..31) ; DH = month (1..12) ; SI = year (1970..2106) ; NOTES: Maxim date/time: 2/7/2106 6:28:15 Sunday (result 0ffffh:0ffffh) ; ----------------------------------------------------------------------------- ; ------------- push registers UnpackUnixTime: push di ; push DI push ax ; push AX push bx ; push BX ; ------------- split to second+minute -> DI, and hours -> DX:AX (0..1193046) ; DX:AX = seconds since 1/1/1970 mov di,60*60 ; DI <- number of seconds per hour xchg ax,si ; SI <- time LOW xor ax,ax ; AX <- 0 xchg ax,dx ; AX <- time HIGH, DX <- 0 div di ; AX <- hours HIGH, DX <- rest xchg ax,si ; AX <- time LOW, SI <- hours HIGH div di ; AX <- hours LOW,DX <- second+minute mov di,dx ; DI <- second+minute mov dx,si ; DX <- hours HIGH ; ------------- split to hour -> BH, and days -> SI (0..49710) ; DX:AX = hours, DI = second+minute mov cx,24 ; CX <- number of hours per day div cx ; DX <- hours, AX <- days mov bh,dl ; BH <- hours xchg ax,si ; SI <- days ; ------------- split second+minute to second -> DI and minute -> BL ; BH = hour, SI = days, DI = second+minute xchg ax,di ; AX <- seconds with minutes mov bl,60 ; BL <- number of seconds per minute div bl ; AL <- minute, AH <- second mov bl,al ; BL <- minute mov al,ah ; AL <- second cbw ; AX = second xchg ax,di ; DI <- second ; ------------- get day of week -> DI HIGH (DI LOW = second) ; BH = hour, BL = minute, SI = days, DI = second mov ax,si ; AX <- days add ax,3 ; AX <- add correction (0 -> Thursday) xor dx,dx ; DX <- 0 mov cl,7 ; CX <- days per week div cx ; DL <- day of week inc dx ; DX <- day of week correction 1.. xchg dh,dl ; DH <- day of week, DL <- 0 or di,dx ; DI <- second, day of week ; ------------- get year - 1970 -> CX (0..136) ; BH = hour, BL = minute, SI = days, DI = second+day of week xor cx,cx ; CX <- year 1970 mov ax,si ; AX <- days add ax,365+366 ; AX <- shift to base 1968 xor dx,dx ; DX <- 0 shl ax,1 ; AX <- days*2 rcl dx,1 ; DX <- carry shl ax,1 ; AX <- days*4 rcl dx,1 ; DX <- carry mov cx,365*3+366 ; CX <- number of days per 4 years div cx ; AX <- year dec ax ; AX <- year - 1 dec ax ; AX <- back to base 1970 xchg ax,cx ; CX <- year ; ------------- get days in year -> SI, correct year -> CX (1970..2106) ; BH = hour, BL = minute, CX = year, SI = days, DI = second+day of week UnpackUnixTime2:call YearToDays ; convert year CX to days->AX, destr.DX sub si,ax ; SI <- days in year cmp cl,130 ; year >= 2100? jb short UnpackUnixTime3 ; year < 2100 cmp si,366 ; 12/32/2104 error je short UnpackUnixTim24 ; invalid date cmp cl,134 ; year 2104? je short UnpackUnixTime3 ; year 2104 cmp si,365 ; invalid 32th Dec ? jne short UnpackUnixTime3 ; no UnpackUnixTim24:inc cx ; CL <- year + 1 xor si,si ; SI <- day 1st Jan UnpackUnixTime3:add cx,1970 ; CX <- year 1970..2106 ; ------------- day (-> DL) and month (-> DH) on 29th Febr leap year ; BH = hour, BL = minute, CX = year, SI = days in year, DI = second+day of week test cl,3 ; leap year? jnz short UnpackUnixTime6 ; not leap year cmp cx,2100 ; year 2100? je short UnpackUnixTime6 ; not leap year cmp si,31+28 ; 29th Febr ? jb short UnpackUnixTime6 ; not leap day ja short UnpackUnixTime5 ; later than 29th Febr mov dx,2*256 + 29 ; DX <- date 29th Febr jmp short UnpackUnixTime8 ; ------------- split days to day -> DL, and month -> DH ; BH = hour, BL = minute, CX = year, SI = days in year, DI = second+day of week UnpackUnixTime5:dec si ; SI <- day - 1 (Februar correction) UnpackUnixTime6:mov ax,si ; AX <- days in year mov dl,31 ; DL <- days in longest month div dl ; AL <- month inc ax ; AL <- month + 1 mov dh,al ; DH <- month cbw ; AX <- month shl ax,1 ; AX <- month*2 xchg ax,si ; SI <- month*2, AX <- days cmp ax,[DaysInYear+si] ; check month jb short UnpackUnixTime7 ; month is OK inc dh ; DH <- month correction inc si ; SI += 1 inc si ; SI <- pointer to next month UnpackUnixTime7:sub ax,[DaysInYear+si-2] ; AX <- day inc ax ; AX <- day + 1 mov dl,al ; DL <- day ; ------------- get output values ; BH=hour, BL=minute, CX=year, DH=month, DL=day, DI=second+day of week UnpackUnixTime8:mov si,cx ; SI <- year mov cx,bx ; CL <- minute, CH <- hour xchg ax,di ; AL <- second, AH <- day of week mov di,sp ; DI <- stack mov [di+1],al ; BH <- second mov [di+2],ah ; AL <- day of week ; ------------- pop registers pop bx ; pop BX (with second) pop ax ; pop AX (with day of week) pop di ; pop DI ret ; ----------------------------------------------------------------------------- ; Convert days (since 1/1/1970) to Unix format (time 0:00:00) ; ----------------------------------------------------------------------------- ; INPUT: AX = days since 1/1/1970 ; OUTPUT: DX:AX = number of seconds since 1/1/1970 0:00:00 Thursday ; NOTES: Maximum date/time: 2/7/2106 6:28:15 (result 0ffffh:0ffffh) ; ----------------------------------------------------------------------------- DayToUnix: mov dx,24*60*60/2 ; DX <- seconds per day / 2 (43200) mul dx ; DX:AX <- convert days to second/2 shl ax,1 ; AX *= 2 rcl dx,1 ; DX:AX <- days converted to seconds ret ; ----------------------------------------------------------------------------- ; Convert Unix format (time ignored) to days (since 1/1/1970) ; ----------------------------------------------------------------------------- ; INPUT: DX:AX = number of seconds since 1/1/1970 0:00:00 Thursday ; OUTPUT: AX = days since 1/1/1970 ; NOTES: Maximum date/time: 2/7/2106 6:28:15 (result 0ffffh:0ffffh) ; ----------------------------------------------------------------------------- UnixToDay: push dx ; push DX push cx ; push CX shr dx,1 ; DX:AX /= 2 rcr ax,1 ; DX:AX = seconds / 2 mov cx,24*60*60/2 ; CX <- seconds per day / 2 (43200) div cx ; AX <- days (0..49710) pop cx ; pop CX pop dx ; pop DX ret ; ----------------------------------------------------------------------------- ; get current time ; ----------------------------------------------------------------------------- ; OUTPUT: BL = hundredth (0..99) ; BH = second (0..59) ; CL = minute (0..59) ; CH = hour (0..23) ; ----------------------------------------------------------------------------- GetTime: push ax ; push AX push dx ; push DX call GetClockTimer ; get clock timer call Clock2Time ; convert clock timer to time pop dx ; pop DX pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; get current date and time ; ----------------------------------------------------------------------------- ; OUTPUT: AL = day of week (1..7, 1=Monday...7=Sunday) ; BL = hundredth (0..99) ; BH = second (0..59) ; CL = minute (0..59) ; CH = hour (0..23) ; DL = day (1..31) ; DH = month (1..12) ; SI = year (1970..2106) ; ----------------------------------------------------------------------------- GetDateTime: call GetTime ; get current time ; === GetDate must follow ! ; ----------------------------------------------------------------------------- ; get current date ; ----------------------------------------------------------------------------- ; OUTPUT: AL = day of week (1..7, 1=Monday...7=Sunday) ; DL = day ; DH = month ; SI = year ; ----------------------------------------------------------------------------- ; ------------- push registers GetDate: push bx ; push BX push cx ; push CX push ax ; push AX ; ------------- get clock timer to update date -> DX:AX call GetClockTimer ; get clock timer ; ------------- get current date mov ax,[Date] ; AX <- current date call DayToUnix ; convert date to Unix format call UnpackUnixTime ; unpack date from Unix format ; ------------- pop registers pop bx ; pop AX mov ah,bh ; AH <- pop AH pop cx ; pop CX pop bx ; pop BX ret ; ----------------------------------------------------------------------------- ; get current date and time with DATETIME structure ; ----------------------------------------------------------------------------- ; INPUT: DI = pointer to destination DATETIME structure ; OUTPUT: AL = day of week (1..7, 1=Monday...7=Sunday) ; ----------------------------------------------------------------------------- ; ------------- push registers GetDateTimeDT: push bx ; push BX push ax ; push AX push cx ; push CX push dx ; push DX push si ; push SI ; ------------- get date and time call GetDateTime ; get current date and time call WriteDT ; write registers to DATETIME structure ; ------------- pop registers pop si ; pop SI pop dx ; pop DX pop cx ; pop CX pop bx ; BX <- pop AX mov ah,bh ; AH <- pop AH (AL=day of week) pop bx ; pop BX ret ; ----------------------------------------------------------------------------- ; get current date in Unix format (time is 0:00:00) ; ----------------------------------------------------------------------------- ; OUTPUT: DX:AX = number of seconds since 1/1/1970 0:00:00 Thursday ; ----------------------------------------------------------------------------- GetDateUnix: mov ax,[Date] ; AX <- current date call DayToUnix ; convert date to Unix format ret ; ----------------------------------------------------------------------------- ; get current time in Unix format ; ----------------------------------------------------------------------------- ; OUTPUT: DX:AX = number of seconds (0..86399) ; ----------------------------------------------------------------------------- GetTimeUnix: push cx ; push CX call GetClockTimer ; get clock timer -> DX:AX call Clock2Unix ; convert clock timer to Unix pop cx ; pop CX ret ; ----------------------------------------------------------------------------- ; get current date and time in Unix format ; ----------------------------------------------------------------------------- ; OUTPUT: DX:AX = number of seconds since 1/1/1970 0:00:00 Thursday ; ----------------------------------------------------------------------------- ; ------------- push registers GetDateTimeUnix:push bx ; push BX push cx ; push CX ; ------------- get time and time in Unix format call GetTimeUnix ; get current time in Unix format xchg ax,cx ; CX <- time LOW mov bx,dx ; BX <- time HIGHT call GetDateUnix ; get current date in Unix format add ax,cx ; AX <- date and time LOW adc dx,bx ; DX <- date and time HIGH ; ------------- pop registers pop cx ; pop CX pop bx ; pop BX ret ; ----------------------------------------------------------------------------- ; Convert clock timer to Unix time (= number of seconds) ; ----------------------------------------------------------------------------- ; INPUT: DX:AX = clock timer (0..1800AFh, interval 54.92549322ms) ; OUTPUT: DX:AX = number of seconds (0..86399) ; CL = hundredth (0..99) ; ----------------------------------------------------------------------------- ; ------------- push registers Clock2Unix: push bx ; push BX push cx ; push CX ; ------------- limit value call ClockValidate ; limit clock timer value ; ------------- multiple clock timer * 5 -> DX:AX (0..7865195) ; Recalc counter to hundredth second: *100*65536/1193180 = *5*65536/59659 mov bx,5 ; BX <- 5 xchg ax,cx ; CX <- timer LOW xchg ax,dx ; DX <- timer HIGH mul bx ; AX <- timer HIGH*5 xchg ax,cx ; AX <- timer LOW, CX <- timer HIGH*5 mul bx ; DX:AX <- timer LOW*5 add dx,cx ; DX <- add timer HIGH ; ------------- calculate hundredths DX:AX/59659*65536 -> CX:AX (0..8639994) mov bx,59659 ; BX <- 59659 div bx ; AX <- quotient, DX <- remainder xchg cx,ax ; CX <- hundredths HIGH xor ax,ax ; AX <- 0, DX:AX = remainder * 65536 div bx ; AX <- hundredths LOW ; ------------- calculate seconds -> DX:AX (0..86399), hundredths -> CL (0..99) xchg ax,cx ; AX <- hundredths HIGH, CX <- LOW xor dx,dx ; DX <- 0 mov bx,100 ; BX <- divisor div bx ; AX <- seconds HIGH, DX <- reaminder xchg ax,cx ; AX <- hundredths LOW, CX <- sec. HIGH div bx ; AX <- seconds LOW, DX <- hundredths xchg dx,cx ; DX <- seconds HIGH, CL <- hundredths ; ------------- pop registers pop bx ; BX <- pop CX mov ch,bh ; CH <- pop CH pop bx ; pop BX ret ; ----------------------------------------------------------------------------- ; Convert clock timer to time ; ----------------------------------------------------------------------------- ; INPUT: DX:AX = clock timer (0..1800AFh, interval 54.92549322ms) ; OUTPUT: BL = hundredth (0..99) ; BH = second (0..59) ; CL = minute (0..59) ; CH = hour (0..23) ; ----------------------------------------------------------------------------- ; ------------- push registers Clock2Time: push ax ; push AX push dx ; push DX ; ------------- calculate seconds -> DX:AX (0..86399), hundredths -> CL (0..99) call Clock2Unix ; convert to Unix time ; ------------- calculate second -> CH (0..59), minutes -> AX (0..1439) mov bx,60 ; BX <- divisor div bx ; AX <- minutes, DX <- second mov ch,dl ; CH <- second ; ------------- calculate hour (0 to 23) and minute (0 to 59) div bl ; AL <- hour, AH <- minute xchg ah,al ; AL <- minute, AH <- hour xchg ax,cx ; CL<-min,CH<-hour,AL<-hund,AH<-sec xchg ax,bx ; BL <- hundreth, BH <- second ; ------------- pop registers pop dx ; pop DX pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; convert time to clock timer ; ----------------------------------------------------------------------------- ; INPUT: BL = hundredth (0..99) ; BH = second (0..59) ; CL = minute (0..59) ; CH = hour (0..23) ; OUTPUT: DX:AX = clock timer (0..1800AFh, interval 54.92549322ms) ; ----------------------------------------------------------------------------- ; ------------- push registers Time2Clock: push bx ; push BX push cx ; push CX ; ------------- limit time values call TimeValidate ; limit time values ; ------------- merge second with hundredth -> BX (0..5999 hundredths) mov al,100 ; AL <- 100 hundredths per second mul bh ; AX <- second in hundredths mov bh,0 ; BX = hundredth add bx,ax ; DX <- second*100 + hundredth ; ------------- merge minute with hour -> AX (0..1439 minutes) mov al,60 ; AL <- 60 minutes per hour mul ch ; AX <- recalc hour to minutes mov ch,0 ; CX = minute add ax,cx ; AX <- hour*60 + minute ; ------------- merge all items -> DX:BX (0..8639999 hundredths) mov dx,6000 ; DX <- 6000 hundredths per minute mul dx ; DX:AX <- hour & minute in hundredths add bx,ax ; BX <- hundredths LOW adc dx,byte 0 ; DX <- hundredths HIGH ; ------------- calculate DX:CX*59659/65536 -> DX:AX (0..7865199) ; Recalc hundredth second to counter: *1193180/100/65536 = *59659/5/65536 xchg ax,dx ; AX <- hundredths HIGH xchg ax,bx ; AX <- hundredths LOW, BX <- HIGH mov cx,59659 ; CX <- 59659 mul cx ; DX <- result LOW (e.g. / 65536) xchg ax,dx ; AX <- result LOW xchg ax,bx ; BX <- result LOW, AX <- hundr. HIGH mul cx ; DX:AX <- result add ax,bx ; AX <- result LOW adc dx,byte 0 ; DX <- result HIGH ; ------------- calculate DX:AX/5 -> DX:AX (0..1573039) mov bx,5 ; BX <- divisor xchg ax,dx ; AX <- HIGH (0..24), DX <- LOW div bl ; AL <- result HIGH, AH <- remainder xchg ax,cx ; CL <- result HIGH, CH <- remainder mov al,ch ; AL <- remainder mov ch,0 ; CX = result HIGH cbw ; AX = remainder xchg ax,dx ; AX <- LOW, DX <- HIGH div bx ; AX <- calculate result LOW xchg dx,cx ; DX <- result HIGH ; ------------- pop registers pop cx ; pop CX pop bx ; pop BX ret ; ----------------------------------------------------------------------------- ; get clock timer ; ----------------------------------------------------------------------------- ; OUTPUT: DX:AX = clock timer (0..1800AFh, interval 54.92549322ms) ; ----------------------------------------------------------------------------- ; ------------- push registers GetClockTimer: push cx ; push CX ; ------------- get clock timer mov ah,0 ; AH <- function code int 1ah ; read clock timer and ax,byte 1 ; AX <- mask 24-hour flag add [Date],ax ; increase current date xchg ax,dx ; AX <- clock timer LOW mov dx,cx ; DX <- clock timer HIGH ; ------------- limit value call ClockValidate ; limit clock timer value ; ------------- pop registers pop cx ; pop CX ret ; ----------------------------------------------------------------------------- ; set clock timer (without updating RTC clock) ; ----------------------------------------------------------------------------- ; INPUT: DX:AX = clock timer (0..1800AFh, interval 54.92549322ms) ; ----------------------------------------------------------------------------- ; ------------- push registers SetClockTimer: push ax ; push AX push cx ; push CX push dx ; push DX ; ------------- limit clock timer value call ClockValidate ; limit clock timer value ; ------------- get clock timer to update date push ax ; push AX push dx ; push DX call GetClockTimer ; get clock timer pop dx ; pop DX pop ax ; pop AX ; ------------- Set new time to clock timer CX:DX xchg ax,dx ; DX <- timer LOW, AX <- timer HIGH xchg ax,cx ; CX <- timer HIGH mov ah,1 ; AH <- function code int 1ah ; set new time ; ------------- pop registry pop dx ; pop DX pop cx ; pop CX pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; get time from RTC (CMOS) clock ; ----------------------------------------------------------------------------- ; OUTPUT: BH = second (0..59) ; CL = minute (0..59) ; CH = hour (0..23) ; ----------------------------------------------------------------------------- ; ------------- push registers GetRTCTime: push ax ; push AX push dx ; push DX ; ------------- get RTC time (BCD), second -> DH, minute -> CL, hour -> CH mov ah,2 ; AH <- function code int 1ah ; get RTC time ; ------------- unpack from BCD to BIN format xchg ax,cx ; AX <- minute and hour call UnpackBCD4Byte ; unpack DX:AX from BCD to BIN format xchg ax,cx ; CL <- minute, CH <- hour mov bh,dh ; BH <- second ; ------------- limit time values mov al,bl ; AL <- push BL call TimeValidate ; limit time values mov bl,al ; BL <- pop BL ; ------------- pop registers pop dx ; pop DX pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; get date from RTC (CMOS) clock ; ----------------------------------------------------------------------------- ; OUTPUT: DL = day (1..31) ; DH = month (1..12) ; SI = year (1970..2106) ; ----------------------------------------------------------------------------- ; ------------- push registers GetRTCDate: push ax ; push AX push cx ; push CX ; ------------- get RTC date (BCD), month -> DH, day -> DL, year -> CH:CL mov ah,4 ; AH <- function code int 1ah ; get RTC time ; ------------- unpack from BCD to BIN format xchg ax,cx ; AX <- year call UnpackBCD4Byte ; unpack DX:AX from BCD to BIN format xchg ax,cx ; CX <- year mov al,100 ; AL <- number of years per century mul ch ; AX <- convert century to year add al,cl ; AL <- add year adc ah,0 ; AX <- year xchg ax,si ; SI <- year ; ------------- limit date values call DateValidate ; limit date values ; ------------- pop registers pop cx ; pop CX pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; get date and time from RTC (CMOS) clock ; ----------------------------------------------------------------------------- ; OUTPUT: BH = second (0..59) ; CL = minute (0..59) ; CH = hour (0..23) ; DL = day (1..31) ; DH = month (1..12) ; SI = year (1970..2106) ; ----------------------------------------------------------------------------- GetRTCDateTime: call GetRTCTime ; get time from RTC (CMOS) clock call GetRTCDate ; get date from RTC (CMOS) clock push ax ; push AX mov al,bl ; AL <- push BL call DateTimeValidate ; limit date and time values mov bl,al ; BL <- pop BL pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; get date and time from RTC (CMOS) clock with DATETIME structure ; ----------------------------------------------------------------------------- ; INPUT: DI = pointer to DATETIME structure ; ----------------------------------------------------------------------------- ; ------------- push registers GetRTCDateTimeDT: push ax ; push AX push bx ; push BX push cx ; push CX push dx ; push DX push si ; push SI ; ------------- get date and time call GetRTCDateTime ; get date and time from RTC clock mov bl,0 ; BL <- 0, hundrendth call WriteDT ; write registers to DATETIME structure ; ------------- pop registers pop si ; pop SI pop dx ; pop DX pop cx ; pop CX pop bx ; pop BX pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; set new time ; ----------------------------------------------------------------------------- ; INPUT: BL = hundredth (0..99) ; BH = second (0..59) ; CL = minute (0..59) ; CH = hour (0..23) ; ----------------------------------------------------------------------------- ; ------------- push registers SetTime: push ax ; push AX push bx ; push BX push cx ; push CX push dx ; push DX ; ------------- limit time values call TimeValidate ; limit time values ; ------------- set time to RTC (CMOS) clock push cx ; push CX mov dx,bx ; DH <- second xchg ax,cx ; AX <- minute and hour call PackBCD4Byte ; pack to BCD format xchg ax,cx ; CX <- minute and hour mov dl,0 ; DL <- don't use day save time mov ah,3 ; AH <- function code int 1ah ; set RTC (CMOS) clock pop cx ; pop CX ; ------------- get clock timer to update date -> DX:AX call GetClockTimer ; get clock timer ; ------------- convert time to clock timer -> DX:AX call Time2Clock ; convert time to clock timer ; ------------- Set new time to clock timer CX:DX xchg ax,dx ; DX <- timer LOW, AX <- timer HIGH xchg ax,cx ; CX <- timer HIGH mov ah,1 ; AH <- function code int 1ah ; set new time ; ------------- pop registers pop dx ; pop DX pop cx ; pop CX pop bx ; pop BX pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; set new date ; ----------------------------------------------------------------------------- ; INPUT: DL = day (1..31) ; DH = month (1..12) ; SI = year (1970..2106) ; ----------------------------------------------------------------------------- ; ------------- push registers SetDate: push ax ; push AX push bx ; push BX push cx ; push CX push dx ; push DX push si ; push SI ; ------------- limit date values call DateValidate ; limit date values ; ------------- set time to RTC (CMOS) clock push dx ; push DX mov ax,si ; AX <- year mov cl,100 ; CL <- 100, divider div cl ; AL <- century, AH <- year xchg al,ah ; AL <- year, AH <- century call PackBCD4Byte ; pack to BCD format xchg ax,cx ; CH <- century, CL <- year mov dl,0 ; DL <- don't use day save time mov ah,5 ; AH <- function code int 1ah ; set RTC (CMOS) clock ; ------------- get clock timer to update date -> DX:AX call GetClockTimer ; get clock timer pop dx ; pop DX ; ------------- set date xor bx,bx ; BH <- 0, second xor cx,cx ; CX <- 0, minute and hour call PackUnixTime ; pack date to Unix format call UnixToDay ; conver Unix format to day mov [Date],ax ; store current date ; ------------- pop registers pop si ; pop SI pop dx ; pop DX pop cx ; pop CX pop bx ; pop BX pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; set new date and time ; ----------------------------------------------------------------------------- ; INPUT: BL = hundredth (0..99) ; BH = second (0..59) ; CL = minute (0..59) ; CH = hour (0..23) ; DL = day (1..31) ; DH = month (1..12) ; SI = year (1970..2106) ; ----------------------------------------------------------------------------- ; ------------- push registers SetDateTime: push bx ; push BX push cx ; push CX push dx ; push DX push si ; push SI ; ------------- limit values of date and time call DateTimeValidate ; limit values of date and time ; ------------- set date and time call SetDate ; set date call SetTime ; set time ; ------------- pop registers pop si ; pop SI pop dx ; pop DX pop cx ; pop CX pop bx ; pop BX ret ; ----------------------------------------------------------------------------- ; set new date and time with DATETIME structure ; ----------------------------------------------------------------------------- ; INPUT: DI = pointer to DATETIME structure ; ----------------------------------------------------------------------------- ; ------------- push registers SetDateTimeDT: push bx ; push BX push cx ; push CX push dx ; push DX push si ; push SI ; ------------- read registers from DATETIME call ReadDT ; read registers from DATETIME ; ------------- limit values of date and time call DateTimeValidate ; limit values of date and time ; ------------- set date and time call SetDate ; set date call SetTime ; set time ; ------------- pop registers pop si ; pop SI pop dx ; pop DX pop cx ; pop CX pop bx ; pop BX ret ; ----------------------------------------------------------------------------- ; Get system timer ; ----------------------------------------------------------------------------- ; OUTPUT: AX = system timer (increasing 0..0ffffh) ; NOTES: Timer counts in frequency 1.193182 MHz, resolution 0.838095 us. ; It takes aprox. 7 us. ; ----------------------------------------------------------------------------- ; ------------- push registers GetSysTimer: push dx ; push DX ; ------------- get system timer mov dl,0 ; DL <- counter index call TimerGetVal ; get counter 0 value -> AX neg ax ; AX <- system timer LOW ; ------------- pop registers pop dx ; pop DX ret ; ----------------------------------------------------------------------------- ; Recalc system timer interval to microseconds ; ----------------------------------------------------------------------------- ; INPUT: AX = system timer interval in ticks (0..0ffffh) ; OUTPUT: AX = time interval in microseconds (0..54924) ; NOTES: Timer counts in frequency 1.193182 MHz, resolution 0.838095 us. ; ----------------------------------------------------------------------------- SysTimerToUs: push dx ; push DX mov dx,54925 ; DX <- multiplier 65535/1.193182 mul dx ; DX <- time in microseconds xchg ax,dx ; AX <- time in microseconds pop dx ; pop DX ret ; ----------------------------------------------------------------------------- ; Recalc microseconds to system timer interval ; ----------------------------------------------------------------------------- ; INPUT: AX = time interval in microseconds (0..54924) ; OUTPUT: AX = system timer interval in ticks (0..0ffffh) ; NOTES: Timer counts in frequency 1.193182 MHz, resolution 0.838095 us. ; ----------------------------------------------------------------------------- UsToSysTimer: push dx ; push DX mov dx,39097 ; DX <- multiplier/2 (1.193182*65536/2) mul dx ; DX <- system timer / 2 shl dx,1 ; DX <- system timer jnc short UsToSysTimer2 ; no overflow xor dx,dx ; DX <- 0 dec dx ; DX <- 0ffffh, limit value UsToSysTimer2: xchg ax,dx ; AX <- system timer value pop dx ; pop DX ret ; ----------------------------------------------------------------------------- ; Wait short time in microseconds ; ----------------------------------------------------------------------------- ; INPUT: AX = required period in us (0..50000) ; NOTES: Interrupt need not be enabled. ; It takes minimal aprox. 15 us, granularity is aprox. 7 us. ; ----------------------------------------------------------------------------- ; ------------- push registers WaitUs: push ax ; push AX push cx ; push CX push dx ; push DX ; ------------- limit value (to avoid overflow or ambiguous results on bound) cmp ax,50000 ; check maximal value jbe short WaitUs3 ; value is OK mov ax,50000 ; limit maximal value ; ------------- recalc time to ticks -> DX WaitUs3: call UsToSysTimer ; recalc time to system timer xchg ax,dx ; DX <- required time ; ------------- save starting value call GetSysTimer ; get system timer xchg ax,cx ; CX <- save old value ; ------------- wait for a given period WaitUs4: call GetSysTimer ; get system timer sub ax,cx ; AX <- difference cmp ax,dx ; time elapsed? jb short WaitUs4 ; continue waiting ; ------------- pop registers pop dx ; pop DX pop cx ; pop CX pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; Wait given time in milliseconds ; ----------------------------------------------------------------------------- ; INPUT: AX = required period in ms (0..65535) ; NOTES: Interrupt need not be enabled. ; ----------------------------------------------------------------------------- ; ------------- push registers WaitMs: push ax ; push AX push cx ; push CX push dx ; push DX ; ------------- save required time -> CX xchg ax,cx ; CX <- required period jcxz WaitMs8 ; no period required ; ------------- prepare time for one wait -> AX WaitMs2: mov ax,50 ; AX <- required time 50 ms cmp cx,50 ; check remaining time jae short WaitMs4 ; longer time mov ax,cx ; AX <- limit time WaitMs4: sub cx,ax ; CX <- decrease counter ; ------------- one wait mov dx,1000 ; DX <- us per ms mul dx ; AX <- time in us call WaitUs ; wait 1000 us or cx,cx ; all time elapsed? jnz short WaitMs2 ; next wait ; ------------- pop registers WaitMs8: pop dx ; pop DX pop cx ; pop CX pop ax ; pop AX ret ; ----------------------------------------------------------------------------- ; Debug check Unix time ; ----------------------------------------------------------------------------- %ifdef DEB_CHECKUNIXTIME ; ------------- mesage CheckUnixTime: mov bx,DebUnixTimeMsg ; BX <- message text string call DispConTextStr ; display text string ; ------------- initialize pointers xor ax,ax ; AX <- 0 mov [DebUnixTimeUnix],ax ; Unix time LOW mov [DebUnixTimeUnix+2],ax ; Unix time HIGH mov si,1970 ; year mov dx,101h ; month and day xor cx,cx ; hour and minute xor bx,bx ; second and hundredth mov di,DebUnixDatetime ; DATETIME structure call WriteDT ; write registers mov byte [DebUnixTimeOld],0ffh ; last displayed day mov byte [DebUnixTimeDayW],4 ; day of week ; ------------- display new year CheckUnixTime2: mov al,[di+DATETIME_Day] ; AL <- day cmp al,[DebUnixTimeOld] ; check last displayed day je short CheckUnixTime3 ; day already displayed mov [DebUnixTimeOld],al ; store new displayer day mov bx,DebUnixTimeMsgY ; BX <- message text string call DispConTextStr ; display text string mov ah,DATEFORM_JAPAN ; AH<-date format Japan (YYYY-MM-DD) call ReadDT ; read registers from DATETIME call DispConDate ; display date call DispConSpc ; display space ; ------------- check unpack from UNIX format CheckUnixTime3: mov ax,[DebUnixTimeUnix] ; AX <- Unix time LOW mov dx,[DebUnixTimeUnix+2] ; DX <- Unix time HIGH call UnpackUnixTime ; unpack Unix time cmp al,[DebUnixTimeDayW] ; check day of week jne short CheckUnixTime32 ; error cmp bh,[di+DATETIME_Sec] ; check second jne short CheckUnixTime32 ; error cmp cl,[di+DATETIME_Min] ; check minute jne short CheckUnixTime32 ; error cmp ch,[di+DATETIME_Hour] ; check hour jne short CheckUnixTime32 ; error cmp dl,[di+DATETIME_Day] ; check day jne short CheckUnixTime32 ; error cmp dh,[di+DATETIME_Month] ; check month jne short CheckUnixTime32 ; error cmp si,[di+DATETIME_Year] ; check year je short CheckUnixTime4 ; all is OK ; ------------- error in function UnpackUnixTime CheckUnixTime32:call CheckUnixTime8 ; display current date and time call DispConByte ; display day of week call DispConSpc ; display space mov ah,DATEFORM_JAPAN ;AL <- date format JAPAN (YYYY-MM-DD) call DispConDate ; display date call DispConSpc ; display space call DispConTime ; display time call DispConSpc ; display space CheckUnixTime34:jmp CheckUnixTime34 ; halt ; ------------- check pack to UNIX format CheckUnixTime4: call ReadDT ; load registers from DATETIME call PackUnixTime ; pack Unix time cmp ax,[DebUnixTimeUnix] ; check Unix time LOW jne CheckUnixTime42 ; error cmp dx,[DebUnixTimeUnix+2] ; check Unix time HIGH je short CheckUnixTime5 ; all is ok ; ------------- error in function PackUnixTime CheckUnixTime42:call CheckUnixTime8 ; display current date and time call DispConDWord ; display counter call DispConSpc ; display space CheckUnixTime44:jmp CheckUnixTime44 ; halt ; ------------- increase Unix time CheckUnixTime5: add word [DebUnixTimeUnix],byte 1 ; increase time LOW adc word [DebUnixTimeUnix+2],byte 0 ; increase time HIGH jnc short CheckUnixTime52 ; continue test ; ------------- all is OK mov bx,DebUnixTimeMsg0 ; BX <- message OK call DispConTextStr ; display message ret ; ------------- increase time CheckUnixTime52:inc byte [di+DATETIME_Sec] ; increase second cmp byte [di+DATETIME_Sec],60 ; overflow? jne short CheckUnixTime7 ; no mov byte [di+DATETIME_Sec],0 ; reset second to 0 inc byte [di+DATETIME_Min] ; increase minute cmp byte [di+DATETIME_Min],60 ; overflow? jne short CheckUnixTime7 ; no mov byte [di+DATETIME_Min],0 ; reset minute to 0 inc byte [di+DATETIME_Hour] ; increase hour cmp byte [di+DATETIME_Hour],24 ; overflow? jne short CheckUnixTime7 ; no mov byte [di+DATETIME_Hour],0 ; reset hour to 0 ; ------------- increase day of week inc byte [DebUnixTimeDayW] ; increase day of week cmp byte [DebUnixTimeDayW],8 ; overflow? jne short CheckUnixTime6 ; no mov byte [DebUnixTimeDayW],1 ; reset day of week to 1 ; ------------- increase date CheckUnixTime6: inc byte [di+DATETIME_Day] ; increase date mov bl,[di+DATETIME_Month] ; BL <- month dec bx ; BX <- correction - 1 mov bh,0 ; BX <- month add bx,DaysInMonth ; BX <- table of days test word [di+DATETIME_Year],3 ; leap year? jnz short CheckUnixTime62 ; not leap year cmp word [di+DATETIME_Year],2100 ; year 2100? je short CheckUnixTime62 ; not leap year add bx,DaysInMonthL - DaysInMonth ; BX <- leap table CheckUnixTime62:mov al,[bx] ; AL <- number of days in this month cmp al,[di+DATETIME_Day] ; check day jae short CheckUnixTime7 ; no overflow mov byte [di+DATETIME_Day],1 ; reset day to 1 inc byte [di+DATETIME_Month] ; increase month cmp byte [di+DATETIME_Month],13 ; overflow? jne short CheckUnixTime7 ; no overflow mov byte [di+DATETIME_Month],1 ; reset month to 1 inc word [di+DATETIME_Year] ; increase year ; ------------- continue test CheckUnixTime7: jmp CheckUnixTime2 ; next test ; ------------- display current date and time CheckUnixTime8: push ax ; push AX push bx ; push BX push cx ; push CX push dx ; push DX push si ; push SI mov bx,DebUnixTimeMsgU ; BX <- error message call DispConTextStr ; display error message mov al,[DebUnixTimeDayW] ; AL <- day of week call DispConByte ; display day of week call DispConSpc ; display space mov ah,DATEFORM_JAPAN; AH <- date format Japan (YYYY-MM-DD) call ReadDT ; read registers from DATETIME call DispConDate ; display date call DispConSpc ; display space call DispConTime ; display time call DispConSpc ; display space mov ax,[DebUnixTimeUnix] ; AX <- Unix time LOW mov dx,[DebUnixTimeUnix+2] ; DX <- Unix time HIGH call DispConDWord ; display Unix time call DispConSpc ; display space mov al,"-" ; AL <- separator call DispConChar ; display separator call DispConSpc ; display space pop si ; pop SI pop dx ; pop DX pop cx ; pop CX pop bx ; pop BX pop ax ; pop AX ret %endif ; ----------------------------------------------------------------------------- ; Constant data ; ----------------------------------------------------------------------------- CONST_SECTION ; ------------- debug check Unix time %ifdef DEB_CHECKUNIXTIME DebUnixTimeMsg: CTEXT 13,10,"DEBUG check Unix time conversions...",13,10 DebUnixTimeMsgY:CTEXT 13,"Checking date " DebUnixTimeMsgU:CTEXT 13,"Error in function UnpackUnixTime!",13,10 DebUnixTimeMsgP:CTEXT 13,"Error in function PackUnixTime!",13,10 DebUnixTimeMsg0:CTEXT 13,"Unix time functions are all OK",13,10 %endif ; ------------- days in month DaysInMonth: db 31,28,31,30,31,30,31,31,30,31,30,31 ; normal year DaysInMonthL: db 31,29,31,30,31,30,31,31,30,31,30,31 ; leap year ; ------------- days in months from start of year DaysInYear: dw 0 ; 1 (0) dw 31 ; 2 (31) dw 31+28 ; 3 (59) dw 31+28+31 ; 4 (90) dw 31+28+31+30 ; 5 (120) dw 31+28+31+30+31 ; 6 (151) dw 31+28+31+30+31+30 ; 7 (181) dw 31+28+31+30+31+30+31 ; 8 (212) dw 31+28+31+30+31+30+31+31 ; 9 (243) dw 31+28+31+30+31+30+31+31+30 ; 10 (273) dw 31+28+31+30+31+30+31+31+30+31 ; 11 (304) dw 31+28+31+30+31+30+31+31+30+31+30 ; 12 (334) ; ----------------------------------------------------------------------------- ; Uninitialised data ; ----------------------------------------------------------------------------- DATA_SECTION ; ------------- debug check Unix time align 4, resb 1 %ifdef DEB_CHECKUNIXTIME DebUnixDatetime:resb DATETIME_size ; current date and time align 4, resb 1 DebUnixTimeUnix:resd 1 ; Unix time DebUnixTimeDayW:resb 1 ; day of week DebUnixTimeOld: resb 1 ; last displayed day %endif ; ------------- current date align 2, resb 1 Date: resw 1 ; current date (days from 1/1/1970)