15

I know that the IBM PC/AT added a battery backed real-time clock chip that independently maintained time whether the system was powered or not. I've also seen many of those big DS1287 clock chips on AT-compatible and older Pentium-era motherboards. I'm curious, though, about how the clock was implemented in the older PC and PC/XT, during the days when the time needed to be manually set on each power-up.

Did these machines have a dedicated clock-and-calendar chip like the PC/AT, just lacking a backup battery? Or was the clock maintained in software, and based off of something like the 18.2 Hz system timer interrupt? If the latter, was it common to lose clock accuracy if the timer rate was changed by a running program?

2
27

Or was the clock maintained in software, and based off of something like the 18.2 Hz system timer interrupt?

This is exactly how time was tracked; you can see the implementation of the timer tick handler in the IBM PC Technical Reference, page A-77. It updates a counter, stored in memory as a double word at 0x0040:0x006C, and checks for elapsing days, setting the flag at 0x0040:0x0070 on date changes. These values can be retrieved using interrupt 0x1A service 0x00.

The “real” date and time are tracked by the operating system; in DOS, they could be retrieved using interrupt 0x21 service 0x2A and set using service 0x2B.

System time handling after boot didn’t change with the advent of battery-backed RTCs: the system date and time were still supposed to be updated using the timer IRQ. The BIOS added functions to provide access to the RTC (e.g. interrupt 0x1A service 0x02 to read the clock time), and DOS used those to initialise its own date and time; but after that the RTC wasn’t used in normal operations.

This is still the case nowadays: the RTC is used to initialise the date and time at boot, and after that time is tracked using timers (not the same ones as in the original IBM PC, but still timers).

If the latter, was it common to lose clock accuracy if the timer rate was changed by a running program?

I don’t remember it being common, but it was possible. I don’t think all that many programs changed the timer rate on the IBM PC back then (pre-AT), and those that did could take the new rate into account before chaining to the previous handler. Programs which had to hook the timer were supposed to hook interrupt 0x1C, not the IRQ-driven interrupt 0x08.

There were other tracking bugs though, for example DOSKEY in DOS 5 could miss date changes (somewhat later than the PC and XT).

9
  • 1
    I've seen a few. worked fine when done carefully (and of course only when being the last added, that's were DOS being single tasked really helped :))
    – Raffzahn
    Sep 2 at 15:22
  • I had a few routines for fast real-time data acquisition that would shut off interrupts (including refresh based on the time tick) for short periods. Never had a problem, but worked hard to not ignore interrupts for too long.
    – Jon Custer
    Sep 2 at 17:41
  • 1
    Most programs that change the timer rate would be games, and while the calculations are simple, and while many games use only an approximation how often to call back the old timer handler, I am still amazed how many games simply used incorrect (possibly typoed) values for calculations, and how many of them did not restore the timer back to 65536 counts per interrupt but 65535.
    – Justme
    Sep 2 at 18:39
  • @Justme Yup, games were exactly what I was thinking of. A lot of early 90s shareware titles used timer frequencies like 560 Hz to stream music data to the AdLib card. I guess they'd have to dispatch the original time-of-day interrupt handler every ~31st interrupt to keep the time reasonably accurate.
    – smitelli
    Sep 2 at 19:42
  • @smitelli By 560Hz you must mean "IMF format". Good thing you mentioned - even Wolfenstein 3D from 1992 gets it slightly wrong, although it uses 700 Hz "IMF format" for playing OPL2 music. By using 1192030 as timer tick rate for reasons unknown, requesting 700 Hz ends up being actually about 701 Hz, and thus calling the original BIOS handler happens 0.1% faster. Definitely not the worst example though.
    – Justme
    Sep 2 at 20:10
13

Or was the clock maintained in software, and based off of something like the 18.2 Hz system timer interrupt?

Exactly that. It is a 32 bit counter incremented by one every time INT 8 is triggered by the 8253 counter #3 (via INT 0).

If the latter, was it common to lose clock accuracy if the timer rate was changed by a running program?

That depends much on the way it was done. If simply changed, yes. But careful handling could prevent any (well most) hickup. Like setting it to hit at 91 Hz and only incrementing every fifth invocation - or better invoke the previous chain to keep all previous listeners in sync. Like explained in this fine article.

4
  • I find it curious that IBM opted to count ticks at a rate of 65,543.42 ticks/hour and count linear ticks, which ends up being rather awkward for any kind of time computation. A rate of 20.0003Hz would have been available and greatly simplified many time computations.
    – supercat
    Sep 2 at 16:19
  • 5
    @supercat I don't find it that curious. Largest possible divisor of 65536 is used to have slowest possible timer tick rate - makes sense from that point of view. And the system timer tick rate does not need easy conversion to wall clock time, as keeping wall clock time was off-loaded to OS. Using integer 65543 ticks per hour would only have error less than 7 ppm, more accurate than what the hardware clock crystal has. What bothers me slightly more is the fact that IBM used ticks per day value of 0x1800b0 with less than 2 ppm error, while 0x1800b2 would be better, but it also does not matter.
    – Justme
    Sep 2 at 18:34
  • @Raffzahn Slight correction; there is no counter #3 on 8253. IRQ 0 (INT 8) is triggered by 8253 counter #0, counter #1 is used for triggering DMA controller to do a memory refresh cycle, and counter #2 is used for speaker.
    – Justme
    Sep 2 at 18:45
  • 1
    @Justme: Many things are supposed to happen at speeds like 1x/second, 2x/second or 4x/second. Having a 20Hz timer tick would facilitate any of those. When using an 18.2Hz timer tick to generate what should be 4Hz events, some events would be 210ms and others 274ms. Also, if one used a 24-bit 20ths-of-second counter, the number of ticks in a day would be a multiple of 256, so rather than using a day-wraparound flag, one could simply have the OS subtract 0x1A5E from the upper 16 bits every time it registers that time has advanced a day.
    – supercat
    Sep 3 at 18:01
4

If the latter, was it common to lose clock accuracy if the timer rate was changed by a running program?

It was certainly possible, yes; it's hard to say how common this kind of distortion was, but it was fairly easily avoidable. A well-behaved program that hooks the timer interrupt needs to call the original handler at its original rate. If it changes the timer rate, it should compensate for that by calling the original handler an appropriate fraction of the time. Fortunately this is possible using a very simple bit of arithmetic.

Besides the solution of running at N times the original rate and passing through 1 out of N interrupts, you could also run the timer at an arbitrary rate and take advantage of the fact that the original timer period is a nice 65,536 ticks. So say you reprogram the timer to a period of 1193 ticks (1000Hz, to within reasonable accuracy). If you start a 16-bit counter at 0 and add 1193 to it every timer interrupt, the times when that add causes an overflow are exactly the times when you need to call the original interrupt handler. The 1ms of added jitter will be unnoticeable, and the long-term rate (what matters for timekeeping) will be just the same as it was before.

The times when this breaks down are when multiple programs try to play with the timer rate (i.e. running a game that reprograms the timer in the presence of a TSR that already hooked the interrupt and reprogrammed the timer), in which case assumptions about the "original rate" will be violated, timekeeping will be lost, and other weird things might happen — or when programmers were simply lazy or didn't know how to do things the right way.

2

For PC XT types, there were multifunction cards using a MC58167 from National Semiconductors. Other RTC chips were also used.

1
  • 1
    True, such cards were available. However, even with such a card, a program was simply run at boot time in AUTOEXEC.BAT to read the time and date from the RTC and tell DOS about time and date. During the DOS session, tracking the passage of time is still implemented by BIOS keeping track of 18.2 Hz system timer interrupts which the DOS uses to keep track of time and date information.
    – Justme
    Sep 4 at 9:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.