jxh@cup.portal.com (Jim - Hickstein) (12/29/88)
Here is the much-requested source for my stupid little program that reads the CMOS clock chip in an AT&T PC6300 and feeds the date and time to DOS. I use it at boot time, since IBM PC-DOS 3.30 doesn't have the AT&T-modified IO system (any 86-DOS old-timers out there?) that "knows" what to do when the DATE and TIME commands are issued, i.e. call the Olivetti BIOS to touch the clock chip directly. I have a big binder full of 7th-generation photocopies of the BIOS listing from an Olivetti M24 (what a 6300 is, really), and managed to glean the following kernels of trivia therefrom. Note that it was written to compile under Logitech Modula-2 release 2, but the gist of it is certainly portable to whatever environment you happen to be suffering from at the moment. Voila! ------ MODULE ATTClock; (* Insofar as I wrote this while an employee of Telcom General Corporation, it is Copyright 1986 Telcom General Corporation, but they're defunct, so draw your own conclusions. AT&T PC 6300 BIOS Interrupt Service Routine INT 1A Read Time: ENTRY (AH) = FE (-2) EXIT (BX) = days since 1984-Jan-01 (1=1984-Jan-01) (CH) = hour (CL) = minute (DH) = second (DL) = hundredth MS-DOS Set Date/Time Function(s) INT 21H al=0 OK, AL=FF invalid Set Date 2B cx year dh mo1-12 dl day 1-31 Set Time 2D ch hour, cl minute, dh seconds, dl hundredths Get Date 2A cx year dh mo1-12 dl day 1-31 al wkdy 0N-6S Get Time 2C ch hour, cl minute, dh seconds, dl hundredths *) FROM SYSTEM IMPORT GETREG, SETREG, SWI, AX, BX, CX, DX; FROM InOut IMPORT Write, WriteCard, WriteString, WriteLn; TYPE Months = (Nul, Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec); VAR year, date, hour, minute, second, hundredth, daysThisYear: CARDINAL; MonthLength: ARRAY Months OF CARDINAL; MonthNames: ARRAY [0..3*13] OF CHAR; month: Months; PROCEDURE Initialize; VAR m: Months; BEGIN year := 1984; MonthNames := '***JanFebMarAprMayJunJulAugSepOctNovDec '; FOR m := Jan TO Dec DO MonthLength[m] := 31 END; MonthLength[Feb] := 28; MonthLength[Apr] := 30; MonthLength[Jun] := 30; MonthLength[Sep] := 30; MonthLength[Nov] := 30; END Initialize; PROCEDURE SetDate; VAR tmp, tmp2: CARDINAL; BEGIN tmp := ORD(month)*256 + date; SETREG(AX, 2B00H) (* Set Date *); SETREG(CX, year); SETREG(DX, tmp); SWI(21H); tmp := hour*256 + minute; tmp2 := second*256 + hundredth; SETREG(AX, 2D00H) (* Set time *); SETREG(CX, tmp); SETREG(DX, tmp2); SWI(21H); END SetDate; PROCEDURE DisplayDate; PROCEDURE Write2Digits(num: CARDINAL); BEGIN IF num < 10 THEN Write('0') END; WriteCard(num, 1) END Write2Digits; VAR i, j: CARDINAL; BEGIN WriteCard(date, 1); Write('-'); i := ORD(month) * 3; FOR j := i TO i+2 DO Write(MonthNames[j]) END; Write('-'); WriteCard(year, 1); Write(' '); Write2Digits(hour); Write(':'); Write2Digits(minute); Write(':'); Write2Digits(second); Write('.'); Write2Digits(hundredth); WriteLn END DisplayDate; PROCEDURE GetTimeFromATT; VAR bx, cx, dx: CARDINAL; BEGIN SETREG(AX, 0FE00H); SWI(1AH); GETREG(BX, bx); GETREG(CX, cx); GETREG(DX, dx); date := bx; hour := cx DIV 256; minute := cx MOD 256; second := dx DIV 256; hundredth := dx MOD 256 END GetTimeFromATT; BEGIN Initialize; GetTimeFromATT; LOOP IF (((year MOD 4) = 0) AND (((year MOD 100) # 0) OR ((year MOD 400) = 0))) THEN daysThisYear := 366; MonthLength[Feb] := 29 ELSE daysThisYear := 365; MonthLength[Feb] := 28 END; IF date >= daysThisYear THEN DEC(date, daysThisYear); INC(year) ELSE EXIT END END; month := Jan; WHILE MonthLength[month] <= date DO DEC(date, MonthLength[month]); INC(month); END; INC(date) (* first date is 1, not 0 *); SetDate; DisplayDate END ATTClock. ------ Jim Hickstein jxh@cup.portal.com ...!sun!portal!cup.portal.com!jxh