
               Real Time Clock / CMOS Setup Reference
                  Version: 1.1 (14 September 1994)
                           By Tom Przeor

AT model was the first in IBM PC family to keep track of time while
switched off. The designers used Motorola MC146818 Real Time Clock
(RTC from now on) chip. This chip provides clock and calendar
functions, few registers to program the chip itself and some 50
bytes of general purpose memory. Typically the RTC chip is used only
on power on - the BIOS will initialize the DOS clock and verify the
configuration. The RTC chip is capable of generating interrupts at
specified frequency or time - we'll get back to it later.

RTC BIOS interface.
-------------------
AT BIOS provides a number of basic functions to use RTC. The
following short list should provide enough information to use them:

RAM data areas used by RTC:

 Addr hex   Size
0040:0098  4 bytes  far pointer to user wait flag
0040:009C  4 bytes  wait count
0040:00A0  1 byte   wait active flag:
                    bit 7 - 1 when wait time elapsed
                    bit 0 - 1 when wait active
                    bits 6-1 - reserved

Int 1Ah function 02h - Get RTC time
        entry:  AH = 02h
        exit :  CF clear if successful, set on error
                CH = hour (BCD)
                CL = minutes (BCD)
                DH = seconds (BCD)
                DL = daylight savings flag
                     (00h standard time, 01h daylight time)

Int 1Ah function 03h - Set RTC time
        entry:  AH = 03h
                CH = hour (BCD)
                CL = minutes (BCD)
                DH = seconds (BCD)
                DL = daylight savings flag (as above)
        exit:   none

Int 1Ah function 04h - Get RTC date
        entry:  AH = 04h
        exit:   CF clear if successful, set on error
                CH = century (BCD)
                CL = year (BCD)
                DH = month (BCD)
                DL = day (BCD)

Int 1Ah function 05h - Set RTC date
        entry:  AH = 05h
                CH = century (BCD)
                CL = year (BCD)
                DH = month (BCD)
                DL = day (BCD)
        exit:   none

Int 1Ah function 06h - Set RTC alarm
        entry:  AH = 06h
                CH = hour (BCD)
                CL = minutes (BCD)
                DH = seconds (BCD)
        exit:   CF clear if successful, set on error
        note:   place address for alarm routine in interrupt 4Ah
                vector before using this service, the alarm occurs
                every 24 hours until turned off, invoking int 4Ah
                each time.

Int 1Ah function 07h - Reset RTC alarm
        entry:  AH = 07h
        exit:   none
        note:   disables alarm set with int1Ah/fn 06h. Don't forget
                to restore old int 4Ah vector.

Int 15h function 83h - Set/Cancel Wait Interval
        subfunction 0 - Set Wait Interval
        entry:  AH = 83h
                AL = 00h
                CX:DX = microseconds to delay
                ES:BX -> byte whose high bit is to be set at end of
                        interval
        exit:   CF clear if successful, set on error

Int 15h function 83h - Set/Cancel Wait Interval
        subfunction 1 - Cancel Wait Interval
        entry:  AH = 83h
                AL = 01h
        exit:   CF clear if successful, set on error
                error status in AH:
                80h invalid command (PC,PCjr)
                86h function not supported (XT and later)

Int 15h function 86h - Wait
        entry:  AH = 86h
                CX:DX = interval in microseconds
        exit:   CF clear if successful (wait interval elapsed)
                CF set on error or AH=83h wait already in progress

There is a difference between functions 83h and 86h. Function 83h
sets a wait interval and allows processing to continue. When the
wait interval ends the user specified flag (pointed by ES:BX) is set
and it is software responsibility to check that flag. That function
can be stopped. Function 86h on the other hand suspends any
processing until specified time interval is elapsed (and cannot be
stopped). These two functions share the same data areas and cannot
be used at the same time. Also note that their resolution is 977
microseconds.

Direct Access to RTC chip.
--------------------------
RTC chip can be accessed through I/O ports 70h and 71h. To read a
byte from the chip, do an OUT 70h,addr; followed by IN al,71H.  To
write a byte to chip, do an OUT 70h,addr; followed by OUT 71h,value.
Example: read equipment byte from CMOS info

mov     al,14h  ;register 14h holds equipment byte
out     70h,al  ;select address 14h on RTC chip
jmp     $+2     ;a slight delay to settle things
in      al,71h  ;AL now has equipment byte

* NOTE: Original MC146818 has 64 registers (00h to 3Fh). Most of the
computers used today have a RTC functional equivalent incorporated
in their 'chipset' and it can have more registers. Those extra bits
are often used by chipset and BIOS designers to store extra
information about things like DRAM wait states, refresh, m/b cache
or user defined hard drive parameters - don't fiddle with them or
you might end up in trouble. Also leave alone the reserved bytes.

The RTC Registers.
------------------
The registers can be divided into three functional groups:

1. Clock/calendar - updated from on chip clock, on IBM compatibles
all quantities are stored in BCD format (ie. 23dec is stored 23h).

2. Status - they affect working of RTC chip itself.

3. CMOS configuration data - general purpose memory not affected and
not affecting the RTC chip.

Here is detailed list of registers (all byte sized, addr in hex):

Addr    Function
====    =========================================

 **     clock/calendar

 00     current second for real-time clock
 01     alarm second
 02     current minute
 03     alarm minute
 04     current hour
 05     alarm hour
 06     current day of week (1=Sunday)
 07     current date of month
 08     current month
 09     current year  (final two digits; eg, 93)

 **     status

 0A     Status Register A - Read/Write except UIP
 ==     =========================================
        ÚÄÄÄÄÄÂÄÄÄÄÄÂÄÄÄÄÄÂÄÄÄÄÄÂÄÄÄÄÄÂÄÄÄÄÄÂÄÄÄÄÄÂÄÄÄÄÄ¿
        ³  7  ³  6  ³  5  ³  4  ³  3  ³  2  ³  1  ³  0  ³
        ³ UIP ³ DV2 ³ DV1 ³ DV0 ³ RS3 ³ RS2 ³ RS1 ³ RS0 ³
        ÀÄÄÄÄÄÁÄÄÄÄÄÁÄÄÄÄÄÁÄÄÄÄÄÁÄÄÄÄÄÁÄÄÄÄÄÁÄÄÄÄÄÁÄÄÄÄÄÙ

        bit 7 - UIP flag, Update In Progress. When set an update
        cycle is in progress and the clock/calendar cannot be
        accessed. When clear, at least 244 microseconds are
        available to access clock/calendar bytes (it's plenty of
        time even on 6MHz AT).

        bits 6-4 - divider bits that define RTC operating frequency.
        ATs have a 32.768 kHz (wrist watch) crystal to operate RTC
        and divider should be set to '010', other values will make a
        time machine from your computer.

        bits 3-0 - Rate Selection bits that define the periodic
        interrupt rate, see another table for details. Default value
        set by BIOS is '0110'.

 0B     Status Register B - Read/Write
 ==     ==============================
        ÚÄÄÄÄÄÂÄÄÄÄÄÂÄÄÄÄÄÂÄÄÄÄÄÂÄÄÄÄÄÂÄÄÄÄÄÂÄÄÄÄÄÂÄÄÄÄÄ¿
        ³  7  ³  6  ³  5  ³  4  ³  3  ³  2  ³  1  ³  0  ³
        ³ SET ³ PIE ³ AIE ³ UIE ³ SQWE³  DM ³24/12³ DSE ³
        ÀÄÄÄÄÄÁÄÄÄÄÄÁÄÄÄÄÄÁÄÄÄÄÄÁÄÄÄÄÄÁÄÄÄÄÄÁÄÄÄÄÄÁÄÄÄÄÄÙ

        bit 7 (SET) - when set to 1, any update in progress is
        aborted and a program may initialize the
        clock/calendar/alarm bytes without an update occurring.
        Setting this bit clears UIE (bit 4). Clearing bit 7 allows
        the update cycle to continue.

        bit 6 (PIE) - Periodic Interrupt Enable, when set the
        periodic interrupt will occur at the frequency specified by
        RS bits in Status Register A.

        bit 5 (AIE) - Alarm Interrupt Enable, when set the alarm
        interrupt will be asserted once for each second that the
        current time matches the alarm time.

        bit 4 (UIE) - Update-ended Interrupt Enable, when set the
        update-ended interrupt will be asserted once each second
        after the end of update cycle. This bit is cleared when SET
        bit goes high but it is not reset when SET is cleared.

        bit 3 (SQWE) - Square Wave Enable, when set, enables the
        square wave output on the SQW pin at the frequency specified
        by the RS bits in the Status Register A. The SQW pin is not
        connected to anything in the AT.

        bit 2 (DM) - Data Mode, indicates mode for clock/calendar
        data: 0=BCD and 1=binary, BIOS setting is 0.

        bit 1 (24/12) - controls hours byte, 0=12-hour and 1=24-hour
        format, BIOS setting is 1.

        bit 0 (DSE) - Daylight Savings Enable, when set two special
        updates will occur: last Sunday in April time will go
        01:59:59 > 03:00:00 and last Sunday in October 01:59:59 >
        01:00:00. BIOS sets it to 0 (ie. no daylight saving).

 0C     Status Register C - Read-only
 ==     =============================
        ÚÄÄÄÄÄÂÄÄÄÄÄÂÄÄÄÄÄÂÄÄÄÄÄÂÄÄÄÄÄÂÄÄÄÄÄÂÄÄÄÄÄÂÄÄÄÄÄ¿
        ³  7  ³  6  ³  5  ³  4  ³  3  ³  2  ³  1  ³  0  ³
        ³ IRQF³  PF ³  AF ³  UF ³  0  ³  0  ³  0  ³  0  ³
        ÀÄÄÄÄÄÁÄÄÄÄÄÁÄÄÄÄÄÁÄÄÄÄÄÁÄÄÄÄÄÁÄÄÄÄÄÁÄÄÄÄÄÁÄÄÄÄÄÙ

        bit 7 (IRQF) - Interrupt Request Flag, when set one of the
        interrupts enabled in Status Register B has occurred.

        bit 6 (PF) - Periodic interrupt Flag, when set the periodic
        interrupt has occurred.

        bit 5 (AF) - Alarm interrupt Flag, when set the alarm
        interrupt has occurred.

        bit 4 (UF) - Update-ended interrupt Flag, when set the
        update-ended alarm interrupt has occurred.

        NOTE: PF, AF, UF are set regardless of corresponding enable
        bits in Status Register B. IRQF will be set only if the
        interrupt flag and its corresponding enable bit are set.
        These four flags are cleared each time Status Register C is
        read. All future interrupts are disabled until this register
        is read - your interrupt handler *must* do it.

        bits 3-0 - reserved, always 0.

 0D     Status Register D - Read-only
 ==     =============================
        ÚÄÄÄÄÄÂÄÄÄÄÄÂÄÄÄÄÄÂÄÄÄÄÄÂÄÄÄÄÄÂÄÄÄÄÄÂÄÄÄÄÄÂÄÄÄÄÄ¿
        ³  7  ³  6  ³  5  ³  4  ³  3  ³  2  ³  1  ³  0  ³
        ³ VRT ³  0  ³  0  ³  0  ³  0  ³  0  ³  0  ³  0  ³
        ÀÄÄÄÄÄÁÄÄÄÄÄÁÄÄÄÄÄÁÄÄÄÄÄÁÄÄÄÄÄÁÄÄÄÄÄÁÄÄÄÄÄÁÄÄÄÄÄÙ

        bit 7 (VRT) - Valid RAM and Time, OK when set, when clear
        indicates power was lost.

        bits 6-0 - reserved.

 **     configuration

 0E     POST diagnostics status byte
 ==     ============================
        bit 7 = 1 clock lost power
        bit 6 = 1 CMOS checksum bad
        bit 5 = 1 invalid configuration found at POST
        bit 4 = 1 memory size compare error at POST
        bit 3 = 1 fixed disk or controller failed
        bit 2 = 1 invalid RTC time (eg. 31 Feb)
        bits 1-0 - reserved

 0F     Shutdown Status Byte
 ==     ====================
        This byte is read upon startup after CPU reset in order to
        determine if the reset cause (to get out of protected mode
        etc.)
        00 - power on reset
        (0 = soft reset (Ctrl-Alt-Del) or unexpected shutdown.  Skip
        POST) - conflicting info from older reference ??????
        01 - memory size pass
        02 - memory test pass
        03 - memory test fail
        04 - POST end, boot system
        05 - JMP DWORD PTR 0:[0467h] with EOI (End Of Interrupt)
        06 - protected tests pass
        07 - protected tests fail
        08 - memory size fail
        09 - INT 15h block move
        0A - JMP DWORD PTR 0:[0467h] without EOI

 10     Diskette drive types
 ==     ====================
        bits 7-4 - drive 0 type (A:)
        bits 3-0 - drive 1 type (B:)
                0000b - no drive
                0001b - 360k
                0010b - 1.2M
                0011b - 720k
                0100b - 1.44M

 11     Reserved
 12     Hard disk drive type
 ==     ====================
        (for drives C: and D:, when between 1 and 14)
        bits 7-4 - fixed disk 0 type (C:)
        bits 3-0 - fixed disk 1 type (D:)
                0000b = no drive
                0001b-1110b = drive type
                1111b = drive 0 (1) type stored at addr 19h (1Ah)
 13     Reserved
 14     Equipment byte
 ==     ==============
        bits 7-6 - no. of floppy drives (00=1, 01=2, 10=3, 11=4)
        bits 5-4 - primary display 00 = none, EGA, VGA ...
                                   01 = 40x25 colour
                                   10 = 80x25 colour
                                   11 = 80x25 monochrome
        bits 3-2 - reserved
        bit 1 =1 if math copro installed
        bit 0 =1 if floppy drive(s) present

 15     Base memory (low byte)
 16     Base memory (high byte)
 ==     =======================
        in kbytes (eg. 0100H=256K, 0200H=512K, 0280H=640K)

 17     Extended memory above 1M (low byte)
 18     Extended memory (high byte) in kbytes

 19     Disk 0 type if (CMOS addr 12H & 0fH) is 0fH
 1A     Disk 1 type if (CMOS addr 12H & f0H) is f0H

 1B-2D  Reserved

 2E     Checksum of CMOS addresses 10H through 20H  (high byte)
 2F     Checksum of CMOS addresses 10H through 20H  (low byte)

 30     Actual extended memory size (low byte)   ???
 31     Actual extended memory size (high byte)  ???
 
 32     Century in BCD (eg. 19h)

 33     Miscellaneous flags
        bit 7 - IBM 128K memory option installed
        bit 6 - used by "Setup" utility (?)
        bits 5-0 - reserved

 34-3F  Reserved

Using RTC hardware interrupt.
-----------------------------
RTC interrupt pin is connected to IRQ8 line in AT bus and generates
int 70h when enabled. The chip can generate three different types of
interrupts: periodic, alarm and update-ended. To use RTC interrupt
first install interrupt service routine and point int 70h vector to
it, then program RTC status registers (details shortly) and 'unmask'
bit 0 of second PIC's mask register at port A1h. You can enable more
than one interrupt type at the same time, in that case your
interrupt handler should check which type has occurred (by reading
Status Register C). In any case your interrupt handler routine must
read Status Register C in order to clear flags and enable interrupts
again.

Update-Ended Interrupt
======================
This is the simplest type - interrupt is generated after each clock
update exactly every 1 second. To enable set bit 4 (UIE) in Status
Register B.

Alarm Interrupt
===============
This is a second type - it generates interrupt at specified time. To
use it first set Alarm Seconds (addr 01h), Alarm Minute (addr 03h)
and Alarm Hour (addr 05h), then set bit 5 (AIE) in Status Register
B. The special value FFh in one of alarm registers will match any
time, eg. FF:FF:00 will generate alarm interrupt every minute,
FF:00:FF will generate interrupt every second during first minute of
every hour.

Periodic Interrupt
==================
The frequency of this interrupt is programmable from 2 to 8192 per
second. To use this type of interrupt first set RS (Rate Select)
bits in Status Register A to the required value:

  RS    Int/sec         Period
 3210      -              -
 0000   none            none
 0001    256            3.90625 ms
 0010    128            7.8125  ms
 0011   8192            122.070 æs
 0100   4096            244.141 æs
 0101   2048            488.281 æs
 0110   1024            976.562 æs
 0111    512            1.93125 ms
 1000    256            3.90625 ms
 1001    128            7.8125  ms
 1010     64            15.625  ms
 1011     32            31.25   ms
 1100     16            62.50   ms
 1101      8            125.0   ms
 1110      4            250.0   ms
 1111      2            500.0   ms

Note: usually this is set to 0110 by BIOS at boot up.

After setting RS bits set bit 6 (PIE) in Status Register B.



The following sources were used to prepare this file:
=====================================================
"The AT Real Time Clock" by Jim Mischel - PC Techniques vol.3/no.2
        which is June/July 1992

TECH Help! Text Version 3.3a (c) 1985,86,87 by Flambeaux Software

famous Ralf Brown's interrupt list

"The New Peter Norton Programmer's Guide to the IBM PC & PS/2" by
        Peter Norton and Richard Wilton

message from DAVID GOODENOUGH in 80XXX Fidonet echo:
                                   ..... AFAIK, there was
only one oversight last time I saw it (several months ago).
To re-enable interrupts, you need to read location 0ch in
the CMOS during your ISR......

===================================================================
If you have any corrections, additions or anything else...
my address: tom@softtech.brisnet.org.au on Internet or
netmail Tom Przeor at 3:640/201 on Fidonet.
                        === End of File ===
