Contributor: GREG VIGNEAULT           

{
MD>What would anyone here recommend as being the best way for DOS
  >protected mode to get the current time of day *without* flipping
  >back to real mode to make a standard DOS call?

 If your code is allowed to talk to the real-time clock (RTC) chip,
 here's some example code to access the RTC directly. The functions
 work solely with 24-hr time format (if needed, internally by the RTC,
 they translate between 12/24-hr times and binary/BCD formats)...
}

(*******************************************************************)
PROGRAM RClock;         { Get/Set Time/Date directly from RTC chip  }
                        { June 9, 1994. Greg Vigneault              }
TYPE  Treg = 0..$D;     { range for time/date register addresses    }
      To23 = 0..23;     { range for hours                           }
      To59 = 0..59;     { range for minutes and seconds             }
VAR   Yr, Mth, Day, DoW, Hr, Min, Sec : BYTE;

FUNCTION RTCbusy:BOOLEAN; BEGIN { RTC time/date being updated?... }
    Port[$70] := $A;;  RTCbusy := (Port[$71] AND 128) = 128;
  END {RTCbusy};

FUNCTION ReadReg (Reg:Treg):BYTE; BEGIN { read an RTC register... }
    IF Reg IN [0..9] THEN REPEAT {wait} UNTIL NOT RTCbusy;
    Port[$70] := Reg;;  ReadReg := Port[$71];
  END {ReadReg};

PROCEDURE WriteReg (Reg:Treg; Data:BYTE); { write RTC reg... }
  VAR temp:BYTE; BEGIN
    IF Reg IN [0..9] THEN BEGIN { time/date reg? }
      REPEAT {wait} UNTIL NOT RTCbusy;
      Port[$70] := $B;; temp := Port[$71];; Port[$71] := temp OR $80;
    END{IF};
    Port[$70] := Reg;;  Port[$71] := Data;
    IF Reg IN [0..9] THEN BEGIN
      Port[$70] := $B;;  Port[$71] := temp AND NOT $80;
    END{IF};
  END {WriteReg};

FUNCTION BCD2Bin (BCD:BYTE):BYTE; BEGIN { xlate BCD to binary... }
    BCD2Bin := (BCD AND $0F) + ((BCD SHR 4) * 10);
  END {BCD2Bin};
FUNCTION Bin2BCD (Bin:BYTE):BYTE; BEGIN { xlate binary to BCD... }
    Bin2BCD := (Bin MOD 10) OR BYTE((Bin DIV 10) SHL 4);
  END {Bin2BCD};

PROCEDURE GetTime (VAR Hr,Min,Sec:BYTE);
  VAR temp:BYTE; BEGIN
    Sec := ReadReg(0);;  Min := ReadReg(2);
    Hr := ReadReg(4);;  temp := Hr;;  Hr := Hr AND NOT $80;
    IF (ReadReg($B) AND 4) <> 4 THEN BEGIN { xlate BCD to bin... }
      Sec := BCD2Bin(Sec);; Min := BCD2Bin(Min);; Hr := BCD2Bin(Hr);
    END{IF};
    IF (ReadReg($B) AND 2) <> 2 THEN  { RTC in 12-hr mode?... }
      IF (temp AND 128) = 128  { P.M.? }
        THEN BEGIN IF (Hr < 12) THEN INC(Hr,12); END
        ELSE IF Hr = 12 THEN Hr := 0;
  END {GetTime};

PROCEDURE SetTime (Hr:To23; Min,Sec:To59);
  VAR temp:BYTE; BEGIN
    temp := BYTE(Hr);
    IF (ReadReg($B) AND 2) <> 2 THEN  { RTC in 12-hr mode?... }
      IF (Hr > 12) THEN DEC(Hr,12) ELSE IF Hr = 0 THEN Hr := 12;
    IF (ReadReg($B) AND 4) <> 4 THEN BEGIN { RTC wants BCD format... }
      Hr := Bin2BCD(Hr);; Min := Bin2BCD(Min);; Sec := Bin2BCD(Sec);
    END{IF};
    IF ((ReadReg($B) AND 2)<>2) AND (temp > 11) THEN Hr := Hr OR $80;
    WriteReg(0,Sec);; WriteReg(2,Min);; WriteReg(4,Hr);
  END {SetTime};

PROCEDURE GetDate (VAR Yr,Mth,Day:BYTE); BEGIN
    Day := ReadReg(7);;  Mth := ReadReg(8);;  Yr := ReadReg(9);
    IF (ReadReg($B) AND 4) <> 4 THEN BEGIN { xlate BCD to binay... }
      Day := BCD2Bin(Day);; Mth := BCD2Bin(Mth);; Yr := BCD2Bin(Yr);
    END; {IF}
  END {GetDate};

PROCEDURE SetDate (Yr,Mth,Day:BYTE); BEGIN
    IF (ReadReg($B) AND 4) <> 4 THEN BEGIN { RTC wants BCD format... }
      Day := Bin2BCD(Day);; Mth := Bin2BCD(Mth);; Yr := Bin2BCD(Yr);
    END{IF};
    WriteReg(7,Day);;  WriteReg(8,Mth);;  WriteReg(9,Yr);
  END {SetDate};

BEGIN {RClock}
  GetTime (Hr,Min,Sec);;  GetDate (Yr,Mth,Day);;  WriteLn;
  Write ('Date is ',Mth,'/',Day,'/',Yr,'. ');
  WriteLn ('Time is ',Hr,':',Min:2,':',Sec:2,'.');
  Write ('(BTW, your RTC is in ');
  IF (ReadReg($B) AND 2) <> 2 THEN Write ('12') ELSE Write ('24');
  Write ('-hour mode using ');
  IF (ReadReg($B) AND 4) <> 4 THEN Write('BCD') ELSE Write('binary');
  WriteLn (' format.)');
END {RClock}.