Skip to content
FreeDOSDeep Dive Published Updated 7 min readViews unavailable

AT Real-Time Clock Interrupts: Periodic Rates, Alarms, and IRQ8 Ownership

Use the AT-compatible RTC periodic and alarm sources without racing BIOS timekeeping, losing status flags, or leaving IRQ8 and CMOS state misconfigured.

The AT-compatible real-time clock (RTC) is more than a battery-backed wall clock. It can produce periodic and alarm interrupts, and its status registers describe which source fired. On a DOS machine, those features are shared with firmware and resident software. A program that enables an RTC interrupt without owning the CMOS register selection, IRQ8 vector, cascade route, and status-clear behavior can break BIOS services or strand the machine in an interrupt storm.

This article concerns the classic Motorola-compatible RTC/CMOS interface documented for the IBM PC/AT. Clone chipsets and virtual machines can emulate it differently. Use a BIOS service when it meets the requirement; program the RTC directly only when the application owns the device path and can restore it. The RTC’s date/time read stability problem is separate and covered in the existing timestamp article.

Registers and interrupt sources

The standard interface selects a CMOS register through I/O port 70h and transfers its value through 71h. On AT-compatible systems, the high bit of the index write also controls the non-maskable-interrupt (NMI) mask. The register selector and NMI state are therefore part of a shared hardware transaction, not a private per-function variable. A driver must serialize access with other CMOS users and preserve the platform’s NMI policy. Do not write a fixed value to port 70h without knowing what state it changes.

Register A contains the divider and rate-select fields. The rate selector controls the periodic source frequency, but the selected rate depends on the RTC’s configured oscillator/divider. Register B enables periodic, alarm, and update-ended interrupts using separate bits and selects data-format behavior such as binary versus BCD and 12-hour versus 24-hour time. Register C reports pending interrupt causes, including periodic, alarm, and update-ended flags, along with an interrupt-request flag. On the documented device, reading register C clears the pending interrupt status. That read-to-clear behavior is essential when servicing the device.

The RTC interrupt reaches the PC/AT’s IRQ8 path, conventionally vector INT 70h, through the secondary interrupt controller and its cascade into the primary PIC. This is a firmware-era routing convention, not an invitation to replace the vector in a running system. The IBM BIOS includes logic for periodic and alarm sources. Other TSRs or a multitasker may also depend on the same IRQ and CMOS state.

Prefer the BIOS event contract when possible

Some AT/PS/2 BIOSes expose event-wait and alarm-related services that use firmware’s own RTC handling. The IBM BIOS Interface reference documents availability by machine class and error reporting through the carry flag and status registers. Probe that interface and handle unsupported functions instead of assuming that every FreeDOS-compatible machine provides a PS/2-era service.

A BIOS wait function may be adequate for a bounded delay or a one-shot event, but it is not equivalent to a high-frequency application timer. The BIOS controls the RTC interrupt routine and decides how to report completion. That preserves ownership boundaries and lets firmware coordinate RTC state. If a program needs a periodic callback with a particular rate, document why a BIOS service does not meet the need before taking direct control.

The BIOS INT 1Ah clock interface serves a different role: it reads or sets system time and the BIOS tick count. It does not make a DOS program the owner of raw RTC interrupts. Avoid mixing direct register writes with BIOS time calls while an interrupt is pending; firmware may observe altered mode, alarm, or enable bits and return unexpected results.

Direct programming requires an ownership plan

Before enabling PIE or AIE, record the current register A/B values, CMOS index/NMI policy, the IRQ8 vector, the relevant master/slave PIC masks, and whether another component owns RTC interrupts. On a system where that state cannot be read or restored safely, do not take direct ownership. The CMOS interface is not automatically protected by DOS, and masking IRQ8 does not stop another component from changing the same registers.

If a standalone driver deliberately owns the RTC interrupt, its handler must identify the cause through register C, acknowledge it using the documented read, update only driver-owned state, and follow the interrupt-controller’s EOI protocol. It must not call DOS, print, allocate memory, or wait in the ISR. If an event callback is needed, signal the foreground loop through a small shared flag or counter and perform application work there.

An RTC periodic source can be much faster than a typical DOS foreground loop. The classic AT BIOS documentation describes a periodic rate around 1.024 kHz for a particular selector setting. That is a hardware interrupt rate, not a recommendation that a DOS application perform work 1,024 times per second. If the program only needs coarse scheduling, use a lower rate or a BIOS tick source. Every interrupt consumes CPU time, and a missed or unacknowledged event can prevent normal system progress.

Alarm bytes and periodic rate are not wall-clock guarantees

An alarm is a comparison against RTC time fields. Its resolution is bounded by the RTC’s update behavior, not by the precision of an application loop. Some RTC-compatible devices implement don’t-care values in alarm fields; do not rely on those encodings unless the specific chipset reference confirms them. Time representation also depends on BCD/binary and 12/24-hour modes. A program that changes register B can reinterpret values written by BIOS software.

Periodic interrupts derive from a divided oscillator. Changing the rate field can interfere with another user’s timing assumptions. Register A also contains status/control fields that should be preserved according to the chipset documentation. Never replace it with a hard-coded constant copied from a different model; read-modify-write only fields the device manual defines as safe and preserve reserved bits.

The RTC is not a durable event scheduler. Power state, battery condition, firmware policy, and virtual machine configuration affect whether an alarm can wake the system or be delivered. Do not claim a background DOS utility will run while the machine is powered down. A periodic interrupt only occurs while the relevant clock and interrupt path are active.

Common failure modes

An interrupt storm usually points to a source that was enabled but not acknowledged, an incorrect vector/EOI path, or register-C semantics that were misunderstood. If the machine hangs as soon as PIE is set, return to the last known-good register state and recheck IRQ ownership before altering PIC masks. If BIOS time or a TSR timer breaks after a utility exits, verify that register A/B and the CMOS index/NMI policy were restored.

An alarm that never fires can be caused by a mismatched time encoding, a disabled alarm-enable bit, unsupported wildcard semantics, a BIOS that owns or clears the event, or an emulator that does not model the source. A periodic rate that differs from expected may reflect divider configuration, a virtual clock, or the selected rate’s oscillator assumptions. Capture the CMOS register values before and after the test, the chipset or VM model, BIOS version, IRQ count, and the exact source flags observed.

Do not troubleshoot RTC problems by repeatedly writing arbitrary values to ports 70h and 71h. That can alter setup data or suppress NMI, obscuring the original issue. Use a disposable emulator snapshot or hardware test platform, and keep a recovery path that can reboot into a known-good profile.

Safe validation strategy

Start with read-only inspection of the BIOS-reported time and machine type. If using a BIOS event service, test its unsupported/error return and cancellation path. For direct hardware work, first test register access with all interrupt-enable bits clear, then verify the observed rate or alarm in a controlled environment before enabling the IRQ. Keep the handler limited to status capture, confirm register C is read once per event, and prove that an abort restores enable bits, vector, masks, and CMOS/NMI state.

Test while the BIOS clock service is also exercised, and verify that system time remains correct after the utility exits. Repeat under the target emulator and on the claimed chipset family. A successful interrupt in one VM is not proof of electrical or firmware behavior on another AT clone.

The safe mental model is that the RTC is a shared peripheral with both calendar and interrupt state. BIOS services are the normal compatibility boundary. Raw periodic or alarm programming is a driver-level ownership decision that must include status acknowledgement, IRQ routing, serialization, and cleanup, not just setting one enable bit.

Related:

Sources:

Comments