home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / assemblr / library / int70 / int70.asm next >
Assembly Source File  |  1993-08-25  |  9KB  |  209 lines

  1. ;  INT70
  2. ;
  3. ;  Demonstrates the use of the Real Time Clock interrupt. This program doesn't
  4. ;  use BIOS services or the BIOS data area, but goes to the hardware directly.
  5. ;  The IRQ masks of both PICS are also reprogrammed, since some BIOS
  6. ;  implementations leave the Real Time Clock IRQ off by default.
  7. ;
  8. ;  Also demonstrates that the interrupt doesn't have to tick at 1024 Hz per se.
  9. ;  The base frequency is 32768 Hz (and the IBM technical reference says it
  10. ;  should remain that value). The lowest 4 bits of status register A divide the
  11. ;  square-wave output frequency (and the interrupt rate). The interrupt rate
  12. ;  is: [32768 SHR (rate-1)] where "rate" is the value of the lowest 4 bits.
  13. ;  This value must be between 3 (8,192 Hz) and 0fh (2 Hz). The default value
  14. ;  of "rate" is 6, giving the default interrupt rate of 1024 Hz.
  15. ;  Adjusting the interrupt frequency does not offset the time of the Real Time
  16. ;  clock. You can set any supported interrupt rate, and the time is maintained
  17. ;  correctly.
  18. ;
  19. ;  The normal way to use the Real Time Clock is by calling the "Wait Event"
  20. ;  function of interrupt 15h. This works, but has some drawbacks:
  21. ;  - It fails if an int 70h hook is already installed (i.e. there is a nested
  22. ;    call to the "Wait Event" function).
  23. ;  - It requires a memory address where it can toggle a bit.
  24. ;  - It turns the timer IRQ off after the time-out specified with the "Wait
  25. ;    Event" function.
  26. ;  - It modifies the BIOS data area, and may therefore give problems in
  27. ;    protected mode. (Note: this program also modifies the BIOS data area, but
  28. ;    only to enhance compatibility with the BIOS. It is not required for the
  29. ;    operation of the program.)
  30. ;
  31. ;  This program should be accompagnied by a text file that explains everything
  32. ;  in more detail.
  33. ;
  34. ;  Assembled with MASM 6.0
  35. ;
  36. ;  August 25, 1993
  37. ;  Thiadmer Riemersma (ITB CompuPhase, The Netherlands)
  38. ;  CompuServe: 100115,2074
  39. ; -----
  40.  
  41. .MODEL  SMALL
  42.  
  43. .STACK  400h                    ; 1K bytes is definitly enough
  44.  
  45. .CODE
  46.  
  47. old70int dd     0
  48.  
  49. main    PROC
  50.         mov     ax, @data               ; set ds=@data
  51.         mov     ds, ax
  52.  
  53.         call    installisr              ; set up ISR and RTC
  54.  
  55.         mov     ax, 0                   ; wait until a key is pressed
  56.         int     16h
  57.  
  58.         call    uninstallisr
  59.  
  60.         mov     ax, 4c00h               ; terminate program
  61.         int     21h
  62. main    endp
  63.  
  64.  
  65. PAUSE   equ     <jmp short $+2>         ; short pauses
  66.  
  67.  
  68. ;  These macros were constructed by analyzing the system BIOS. It is important
  69. ;  to:
  70. ;  - disable interrupts while reading/writing CMOS values (even the NMI)
  71. ;  - leave the index register (70h) point at status register D (index 0dh)
  72. ;  - insert a pause between reading and writing to the ports
  73. ;  - always access port 71h (by reading or writing) after setting the index of
  74. ;    the index register (70h)
  75. ; -----
  76. ReadRTC macro   index
  77.         pushf                   ;; save flags
  78.         cli                     ;; no interrupts while changing CMOS values
  79.         mov     ax, index
  80.         or      al, 80h         ;; set NMI bit, disable even NMI
  81.         out     70h, al
  82.         PAUSE                   ;; pause between accessing RTC ports
  83.         in      al, 71h
  84.         push    ax              ;; save value read at indicated index
  85.         PAUSE
  86.         mov     al, 0dh         ;; leave index at status register D, and...
  87.         out     70h, al         ;; ...enable NMI again
  88.         PAUSE                   ;; *always* read/write port 71h after...
  89.         in      al, 71h         ;; ...writing to port 70h
  90.         pop     ax
  91.         popf                    ;; restore flags (includes the interrupt flag)
  92. endm
  93.  
  94. SetRTC  macro   index, value
  95.         pushf                   ;; save flags
  96.         push    ax
  97.         cli                     ;; No interrupts while changing CMOS values
  98.         mov     ax, index
  99.         or      al, 80h         ;; set NMI bit, disable even NMI
  100.         out     70h, al         ;; write index
  101.         PAUSE
  102. ifdifi  <value>, <al>
  103.         mov     al, value       ;; value is not "al", move it into al
  104. else
  105.         pop     ax              ;; value is "al", restore "al" from the stack
  106.         push    ax              ;; save ax again
  107. endif
  108.         out     71h, al         ;; write value at indicated index
  109.         PAUSE
  110.         mov     al, 0dh         ;; leave index at status register D, and...
  111.         out     70h, al         ;; ...enable NMI again
  112.         PAUSE                   ;; *always* read/write port 71h after...
  113.         in      al, 71h         ;; ...writing to port 70h
  114.         pop     ax              ;; restore ax
  115.         popf                    ;; restore flags (including interrupt flag)
  116. endm
  117.  
  118.  
  119. installisr proc
  120.         ;  Install ISR for Real Time Clock (RTC)
  121.         mov     ax, 3570h               ; get interrupt vector 70h (RTC)
  122.         int     21h
  123.         mov     word ptr cs:[old70int], bx ; store the curent vector
  124.         mov     word ptr cs:[old70int+2], es
  125.         mov     dx, offset cs:int70proc ; new ISR for int 70h
  126.         push    ds                      ; save ds
  127.         mov     ax, @code
  128.         mov     ds, ax                  ; copy CS to DS
  129.         mov     ax, 2570h               ; set interrupt vector nr. 70h
  130.         int     21h
  131.         pop     ds                      ; restore ds
  132.  
  133.         ;  Now initialize the RTC
  134.         ReadRTC 0bh                     ; read status register B
  135.         or      al, 40h                 ; set periodic interrupt bit
  136.         SetRTC  0bh, al
  137.         ReadRTC 0ch                     ; clear pending interrupt with a read
  138.  
  139.         ;  Alter the interrupt rate (to the slowest rate: 2 ticks/second)
  140.         ReadRTC 0ah                     ; alter the interrupt rate
  141.         and     al, 0f0h                ; clear "rate selection bits"
  142.         or      al, 0fh                 ; set rate selection to 2 ticks/second
  143.         SetRTC  0ah, al
  144.  
  145.         ;  Finally, initialize the secondary PIC
  146.         cli                             ; no interrupts while programmning PIC
  147.         in      al, 0a1h                ; read mask of secondary PIC
  148.         and     al, 0feh                ; clear bit 0 (IRQ8=RTC)
  149.         PAUSE                           ; pause between reads and writes
  150.         out     0a1h, al                ; store mask
  151.         sti                             ; re-enable interrupts
  152.         ret
  153. installisr endp
  154.  
  155.  
  156. uninstallisr proc
  157.         ;  Clean up the RTC
  158.         ReadRTC 0bh                     ; read status register B
  159.         and     al, 0bfh                ; clear periodic interrupt bit
  160.         SetRTC  0bh, al
  161.         ReadRTC 0ah                     ; reset the interrupt rate
  162.         and     al, 0f0h                ; clear "rate selection bits"
  163.         or      al, 06h                 ; set rate selection to 1024 Hz
  164.         SetRTC  0ah, al
  165.  
  166.         ;  Reset interrupt vectors
  167.         push    ds                      ; save ds
  168.         mov     ax, 2570h               ; reset int 70h
  169.         lds     dx, cs:[old70int]       ; ds:dx -> old interrupt vector
  170.         int     21h
  171.         pop     ds                      ; reset ds
  172.  
  173.         ;  Most BIOSes never reset the secondary PIC, so we don't either. IRQ 8
  174.         ;  is no longer generated anyway.
  175.         ret
  176. uninstallisr endp
  177.  
  178.  
  179. ;  The new int 70h ISR. Toggles the "speaker enable" bit to get an audible
  180. ;  indication that the ISR works.
  181. ;
  182. ;  Note:
  183. ;  We don't call the previous interrupt 70h handler, because the default
  184. ;  handler in the BIOS adjusts fields in the BIOS data area and may switch
  185. ;  itself off after a specified time-out. The problems for dealing with the
  186. ;  default interrupt handler is probably the main reason that the RTC is not
  187. ;  more widely used.
  188. ; -----
  189. int70proc proc   FAR
  190.         push    ax
  191.         push    es
  192.         in      al, 61h                 ; read current value of register 61h
  193.         xor     al, 2                   ; toggle 2nd bit
  194.         out     61h,al                  ; enable/disable speaker
  195.  
  196.         ReadRTC 0ch                     ; read status register C to clear...
  197.                                         ; ...pending interrupt
  198.         cli                             ; avoid interrupts between both EOIs
  199.         mov     al, 20h                 ; send non-specific EOI...
  200.         out     0a0h, al                ; ...to secondary PIC (slave) and...
  201.         out     20h, al                 ; ...to primary PIC (master)
  202.         pop     es
  203.         pop     ax
  204.         iret
  205. int70proc endp
  206.  
  207.  
  208.         end main
  209.