home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / assemblr / library / int70 / int70.txt < prev   
Text File  |  1993-08-25  |  15KB  |  274 lines

  1. Periodic Interrupts with the Real Time Clock
  2. ============================================
  3.  
  4.  
  5. Acknowledgements
  6. ----------------
  7. Terry Greenaway (AVIX Inc.) pointed out differences between AMI and Phoenix
  8.   BIOSes and limitations of the frequency range of the periodic interrupts.
  9. Nu-Mega, for their wonderful Soft-ICE debugger. Perfect equipment for snooping
  10.   around in TSRs and the system BIOS.
  11.  
  12.  
  13. Introduction
  14. ------------
  15.  
  16. The original IBM PC only kept the date and time while it was running. Each time
  17. you booted the computer, it reset the date to January 1, 1980, 0:00 hour. At
  18. these days, the AUTOEXEC.BAT file usually contained the DATE and TIME commands,
  19. so that you were prompted for the proper date at each boot.
  20.  
  21. The clock that keeps the current time and date is a 8253 or 8254 chip (or
  22. compatible) with three porogrammable counters. Two of these counters are used
  23. for DRAM refresh and to drive the speaker. The third one is hooked to IRQ 0
  24. (interrupt 8) and the default handler for interrupt 8 in the system BIOS
  25. adjusts the current time in the BIOS data area at each "tick".
  26.  
  27. Over time, many programs that needed periodic service also hooked interrupt 8.
  28. The PRINT.COM program that comes with DOS is a good example. Some programs also
  29. require a faster periodicy than the 18.2 ticks/second standard rate (for
  30. example, execution profilers). So they reprogram the timer.
  31.  
  32. Here the problems begin. First of all, the default BIOS ISR must still see 18.2
  33. ticks per second to keep the time straight. For example, when you reprogram the
  34. timer to tick at 91 Hz and pass only one out of 5 interrupts to the previous
  35. interrupt handler, this one sees 91/5 = 18.2 ticks per second. If the new
  36. timer frequency is not a multiple of 18.2, the process is slightly more
  37. complicated, but it is still possible to pass 18.2 interrupts per second to
  38. the previous handler on the average.
  39.  
  40. But this trick only works if the ISR that uses the higher interrupt frequency
  41. is the last in the chain of interrupt 8 hooks. If another ISR hooks behind it,
  42. that one too will see the higher interrupt rate (and possibly draw incorrect
  43. conclusions about when to pop up). Worse yet, if that other routine also
  44. reporgrammed the timer... In conclusion, when you reprogram the timer in a TSR
  45. (where you cannot guarantee that you are the last in the chain), you may
  46. encounter conflicts with other TSRs and application programs. Microsoft Windows
  47. has a virtual timer device (VTD) to solve such conflicts between windows
  48. applications and DOS boxes.
  49.  
  50. These problems are what led me to investigate the use of another timer. One
  51. that also generates interrupts. One that almost no one uses.
  52.  
  53.  
  54. The Real Time Clock
  55. -------------------
  56.  
  57. The use of the Real Time Clock is not a general solution to the conflicts
  58. outlined above. If enough programs use and/or reprogram the Real Time Clock, we
  59. have exactly the same situation. But for now, the use of the Real Time Clock
  60. has worked for me in situations that the interrupt 8 method did not.
  61.  
  62. Why isn't the Real Time Clock more widely used? There may be several reasons. I
  63. can think of these:
  64. * The Real Time Clock is not available on all machines. The Real Time Clock was
  65.   introduced with the IBM PC AT, and most PC XT style computers do not have the
  66.   circuitry. This means that you also have to detect wether Real Time Clock
  67.   services are available if you intend to use them.
  68. * The Real Time Clock became available when the interrupt 8 hooking and timer
  69.   reprogramming had already entered the folklore. People just kept going on the
  70.   same track.
  71. * The Real Time Clock is less flexible; it handles only 15 possible interrupt
  72.   rates between 2 Hz and 32767 Hz (theoretically, that is; in practice, the
  73.   interrupt rate cannot go higher than 8 kHz on most systems).
  74. * The default interrupt handler has the irritating behavoir of switching the
  75.   Real Time Clock interrupt off after a time-out expires.
  76. * The Real Time Clock, and especially the use of the interrupt on IRQ 8
  77.   (interrupt 70h), is ill documented. In fact, I found out most of this by
  78.   diving into the BIOS with Nu-Mega's Soft-ICE debugger.
  79.  
  80.  
  81. The RTC/CMOS chip
  82. -----------------
  83.  
  84. The chip that contains the Real Time Clock is a Motorola MC146818A CMOS chip.
  85. In addition to the Real Time clock, it contains 64 bytes of non-volatile RAM
  86. for machine status information. (This is the CMOS data that holds vital
  87. information on the type of the hard disk, the amount of memory, etc.)
  88.  
  89. The RTC/CMOS chips is programmed through the I/O addresses 70h and 71h. Port
  90. 70h is the index register and port 71h is the data register. Both ports can be
  91. read or written. All internal registers of the RTC/CMOS chips are accessed by
  92. setting an index at port 70h and reading from or writing to port 71h. To use
  93. the RTC/CMOS chip for periodic interrupts, we only need to consider four of
  94. these internal registers: the status registers A to D.
  95.  
  96. There are a few caveats when programming the RTC/CMOS chip. First of all, the
  97. index register is usually set to status register D, and it should remain set to
  98. this register. Secondly, after writing to port 70h, you must read from, or
  99. write to port 71h. There is no real purpose in writing to port 71h when status
  100. register D is selected, because it only indicates wether the RTC/CMOS chip
  101. still has power (battery). So after you read or write a value to an internal
  102. register, you reset the index register (port 70h) to 0Dh (status register D),
  103. and then do a read from port 71h.
  104.  
  105. Finally, there should not be a long delay between writing to port 70h and
  106. reading from or writing to port 71h. Waiting too long between the two
  107. operations can cause malfunction of the RTC/CMOS chip. Interrupts must be
  108. disabled while programming the RTC. The non-maskable interrupt (NMI) must also
  109. be disabled.
  110.  
  111. The NMI mostly requires you to reboot, so you may be inclined to say "What the
  112. heck, why bother to keep the chip in a good shape at an NMI. When an NMI
  113. occurs, I have a system failure and I'll probably need to do a clod start. So
  114. the chip restarts with a clean state anyway". Not so with the RTC/CMOS chip.
  115. Remember, this chip continues to work when the computer is switched off. The
  116. BIOS does not initialize the chip at boot time; on the contrary, the system
  117. reads values from the chip to determine vital parameters such as memory size
  118. and the fixed disk type. Malfunction in the RTC/CMOS chip is to be avoided at
  119. all cost. That is why you want to avoid an NMI when modifying the RTC, and turn
  120. it on afterwards.
  121.  
  122. Another reason to toggle the NMI is that it is equally simple to turn it off
  123. and on as to leave it unchanged. The NMI mask bit is accessed at the same I/O
  124. address as the RTC/CMOS index register: port 70h. Bit 7 of port 70h masks or
  125. unmasks the NMI at the same time as selecting the index for port 71h.
  126.  
  127. Now that the basics of the RTC/CMOS programming are covered, we can return to
  128. the main course: programming the RTC to generate interrupts.
  129.  
  130. Status register A is used to select an interrupt rate. The basic oscillator
  131. frequency (in the bits 4-6 of status register A) is set to 32,768 Hz. This
  132. setting indicates what kind of crystal is connected to the oscillator circuit
  133. of the MC146818A chip. On the IBM PC-AT, this a a 32 kHz crystal. Choosing a
  134. different frequency setting in status register A can cause the RTC/CMOS chip to
  135. update the time incorrectly.
  136.  
  137. The lower four bits (0-3) of status register A select a divider for the
  138. 32,768 Hz frequency. The resulting frequency is used for the periodic interrupt
  139. (IRQ 8). The system initializes these bits to 0110 binary (or 6 decimal). This
  140. selects a 1,024 Hz frequency (and interrupt rate). Setting the lowest four bits
  141. to a different value changes the interrupt rate *without* interfering with the
  142. time keeping of the RTC/CMOS chip.
  143.  
  144. The formula to calculate the interrupt rate is:
  145.  
  146.   freq. = 32768 >> (rate-1)
  147.  
  148. where *rate* is the value of the lower four bits of status register A. This
  149. value must be between 1 and 15 (selecting 0 stops the periodic interrupt). The
  150. interrupt frequency you can choose is thus always a power of 2 between 2 Hz and
  151. 32768 Hz. There is a caveat, however. With an input signal of 32768 Hz, the
  152. timer output 'rolls over' if you set the value *rate* to 2 or 1. Instead of
  153. producing periodic interrupts of 61.0 uS or 30.5 uS respectively, they produce
  154. 7.81 mS and 3.91 mS interrupts. The fastest interrupt rate you can generate is
  155. 8 kHz (122 uS interrupts), by setting *rate* to 3. Higher frequencies requires
  156. a higher base frequency, and this would require a different crystal than is
  157. installed in the IBM PC-AT.
  158.  
  159. Status register B contains a number of flags. We are only interested in one of
  160. these flags: the "Periodic Interrupt Enable" or PIE bit. Setting this bit is
  161. the only thing left to start generating interrupts to INT 70h. By the way, the
  162. choice of IRQ, interrupt and I/O port numbers is very confusing. When IRQ 8
  163. fires, it generates INT 70h. This set programmed as such in the seondary PIC,
  164. it has nothing to do with I/O port 70h, that is used to program the RTC/CMOS
  165. chip. Also, INT 8 belongs to the standard timer, IRQ 8 to the RTC. We have just
  166. to be extra precise when talking about this subject.
  167.  
  168. When an IRQ 8 fires and interrupt 70h is called, status register C holds a bit
  169. mask that tells what kind of interrupt occured: periodic interrupt, alarm
  170. interrupt or update ended interrupt. And unless you read status register C,
  171. IRQ 8 will not be generated again. This means that you must read status
  172. register C inside your ISR for interrupt 70h even when you normally don't care
  173. about its contents. Otherwise you will only see a single interrupt.
  174.  
  175. The bits in status register C are not used in the example program. They are
  176. useful when several interrupts if the RTC are connected to IRQ 8. The bits in
  177. status register C let you detect what interrupt caused IRQ 8.
  178.  
  179. The last thing we have to cover before leaving the RTC/CMOS chip is how to
  180. detect the chip. Two common methods are to check that the I/O ports are
  181. functioning (write a value into one of them and read it back), and to use a
  182. BIOS function that also uses the hardware and check the results. Although it
  183. looks cleaner, the BIOS function should be used with caution, because it might
  184. use different hardware to achieve the desired result. Indeed, the IBM PS/2
  185. model 30, running on an 8086 processor, has Real Time Clock services, but not
  186. with the same hardware. The model 30 uses a VLSI gate array the keyboard
  187. controller, mouse controller, real time clock and interrupt controller. There
  188. is only one interrupt controller (compatible with the 8259A PIC chip in the
  189. PC XT and AT computers), but all functionality is jammed inside the 8 lines of
  190. the PIC by connecting the keyboard, the mouse and the Real Time Clock to IRQ 1.
  191.  
  192.  
  193. The Peripheral Interrupt Controllers
  194. ------------------------------------
  195.  
  196. The Peripheral Interrupt Controller (PIC) converts IRQ signals to hardware
  197. interrupts. The original PC had only one PIC (chip 8259A) for eight IRQ lines.
  198. These IRQs 0 to 7 are normally redirected to (hardware) interrupts 8 to 0fh.
  199. Many DOS extenders reprogram the primary PIC to relocate the interrupt range,
  200. because interrupts 8 to 0fh collide with the processor exception interrupts.
  201.  
  202. The IBM PC-AT and compatibles have two PCI chips in a chain. The second PIC was
  203. chained to IRQ 2 of the first PIC. The RTC is connected to the first line of
  204. the secondary PIC. The IRQ lines of the secondary PIC are usually translated to
  205. interrupts 70h to 77h.
  206.  
  207. We deal with the PICs at two places. The first one is that an ISR for a
  208. hardware interrupt should send an "end of interrupt" (EOI) signal to the PICs
  209. before returning. Otherwise the PIC will not generate an interrupt for the IRQ
  210. or any IRQ of a lower level. In the case of the RTC, we must send a non-
  211. specific EOI to both PICs (since they are chained).
  212.  
  213. Each PIC has an 8 bit mask that disables selected IRQs. Masked IRQs are not
  214. passed through to the microprocessor. The BIOS by American Megatrends Inc.
  215. (AMI) disables IRQ 8 (bit 0 in the mask of the secondary PIC) at startup. We
  216. need to unmask IRQ 8 when initializing the RTC. The BIOS by Phoenix enables
  217. IRQ 8 by default, but it doesn't harm to enable it again. Although the
  218. secondary PIC is chained to the primary PIC on the IRQ 2 line, it is not
  219. necessary to repogram the mask of the first PIC. IRQ 2 is always enabled, since
  220. the hard disk and other essential hardware is also connected to the secondary
  221. PIC.
  222.  
  223.  
  224. Compatibility with the BIOS
  225. ---------------------------
  226.  
  227. The goal is to be able to jump to the previous int 70h handler after your
  228. handler has done its work. This is common practice when writing ISRs. But in
  229. the case of the RTC, you have to deal with the irritating feature of the
  230. default int 70h handler, that shuts the RTC down after the time period in the
  231. BIOS data area has expired.
  232.  
  233. My demo program avoids all this by *not* jumping to the previous int 70h
  234. handler. After all, it intents to show the working of the RTC, not that of the
  235. BIOS.
  236.  
  237. A simple way to solve this is to disallow the BIOS functions that use the RTC.
  238. To do this, you set the byte at address 0040h:00a0h to 1. This value tells the
  239. BIOS that the RTC is in use, and makes functions 83h and 86h of interrupt 15h
  240. fail (return with carry flag set). Then, before jumping to the previous int 70h
  241. handler, you store at address 0040h:009b a double word value that is at least
  242. 976. The default interrupt handler subtracts 976 from the value at that address
  243. and halts the RTC periodic interrupts if at drops below zero (976 is the time
  244. in microseconds that passes between two invokations of int 70h if the RTC is
  245. ticking at its default frequency of 1024 Hz).
  246.  
  247. If you require that the BIOS functions 83h and 86h of interrupt 15h keep
  248. working, the best solution probably is to take over interrupt 15h. You then
  249. need to simulate these functions. That means that you must update the BIOS data
  250. area, detect a time-out and handle accoringly. If you choose this path, remind
  251. that the default int 70h handler also issues int 4ah on time-out (in addition
  252. to shutting the RTC periodic interrupt down).
  253.  
  254.  
  255. Strapping it all together (the program)
  256. ---------------------------------------
  257.  
  258. I only give the assembler source, not an executable version of the demo. The
  259. program does preciously little; its only purpose is to show the information in
  260. this text file in its context.
  261.  
  262. Now that we have finished our journey through the peculiarities of the Real
  263. Time Clock, it is time to discuss where it can be used. Well, I had a real
  264. purpose to investigate the RTC, but I can't talk about it now. I can think of
  265. task switchers, animation, but it sounds far away to me. If you use the
  266. periodic interrupt of the RTC, I would like to hear about it. Similarly, if
  267. you have any problems with this demo program (incompatible hardware or BIOSes),
  268. drop me a note.
  269.  
  270.  
  271. Thiadmer Riemersma
  272. ITB CompuPhase, The Netherlands
  273. CompuServe: 100115,2074
  274.