home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 15 / 15.iso / s / s300 / 1.ddi / CHAP2 / TIMEINTA.ASM < prev    next >
Encoding:
Assembly Source File  |  1988-02-19  |  8.2 KB  |  348 lines

  1. ;***********************************************************************
  2. ;
  3. ; FILE
  4. ;    timeinta.asm  -  timer interrupt demo, assembly portion
  5. ;
  6. ; REMARKS
  7. ;    This module implements some of the very basic functions needed
  8. ;    to set up a timer interrupt service routine.
  9. ;
  10. ;    The C language service routine MUST be named tick() and the
  11. ;    low level interrupt handler is named here as tmrisr().
  12. ;
  13. ;    Note that this module is designed to be used with Microsoft C
  14. ;    version 4.00 and above; it will probably work with version 3.00
  15. ;    also.  All global names are preceeded by an underscore and you
  16. ;    must assemble using the /ml flag to preserve case sensitivity:
  17. ;
  18. ;        masm timeinta /ml;
  19. ;
  20. ; LAST UPDATE
  21. ;    15 January 1988  by  Haam
  22. ;        special version to demo how to roll your own timer isr
  23. ;
  24. ;    Copyright(c) 1986-1988  D.M. Auslander and C.H. Tham
  25. ;
  26. ;***********************************************************************
  27.  
  28.     EOIPORT        EQU        20h        ; where to send the EOI byte
  29.     SEOI        EQU        60h        ; specific EOI byte for the timer
  30.  
  31.     INCLUDE model.h                ; memory model definitions
  32.  
  33. IF LCODE
  34.     EXTRN    _tick:FAR            ; tick is in different code segment
  35. ENDIF
  36.  
  37.     INCLUDE prologue.h            ; setup stuff
  38.  
  39. IFE LCODE
  40.     EXTRN    _tick:NEAR            ; tick is in same code segment
  41. ENDIF
  42.  
  43.  
  44.     PUBLIC    _tmrisr                ; this means tmrisr() is visible
  45.  
  46.     PUBLIC _setivec, _getivec
  47.     PUBLIC _enable, _disable
  48.  
  49.  
  50.  
  51. ;----------------------------------------------------------------------
  52. ; PROCEDURE
  53. ;    TMRISR  -  timer interrupt service routine
  54. ;
  55. ; SYNOPSIS
  56. ;    void tmrisr(void), vectored to by timer interrupt
  57. ;
  58. ; REMARKS
  59. ;    Saves the registers and switch to the program's data segment which
  60. ;    is defined by DGROUP in all memory models.  The CPU's interrupt 
  61. ;    response is enabled with a sti instruction almost immediately to
  62. ;    allow higher priority interrupts to interrupt this interrupt, not
  63. ;    that it makes much difference in the IBM-PC since the timer is the
  64. ;    highest priority interrupt.
  65. ;
  66. ;    A specific EOI (end-of-interrupt) byte is sent to the 8259 Interrupt
  67. ;    Controller at the end of the service function, tick().  This tells
  68. ;    the 8259 that we are done servicing the timer interrupt.  Without
  69. ;    an EOI notification, the 8259 will not allow another timer interrupt
  70. ;    (plus all lower priority interrupts) to be passed to the CPU.
  71. ;
  72. ;    There are ways around this, for example, by using the special mask
  73. ;    mode, but that is beyond the scope of this exercise.
  74. ;
  75. ; LAST UPDATE
  76. ;    10 January 1988
  77. ;----------------------------------------------------------------------
  78.  
  79. IF LCODE
  80. _tmrisr        PROC    FAR
  81. ELSE
  82. _tmrisr        PROC    NEAR
  83. ENDIF
  84.  
  85.     sti                            ; enable CPU's interrupt response
  86.     
  87.     push    ax                    ; save registers in pusha order
  88.     push    cx
  89.     push    dx
  90.     push    bx
  91.     push    bp
  92.     push    si
  93.     push    di
  94.  
  95.     push    ds                    ; save data and extra segments
  96.     push    es
  97.  
  98.     mov        ax, SEG DGROUP        ; switch to program's data segment
  99.     mov        ds, ax
  100.  
  101.     call    _tick
  102.  
  103.     mov        al, SEOI            ; send specific EOI
  104.     out        EOIPORT, al
  105.  
  106.     pop        es                    ; restores data and extra segments
  107.     pop        ds
  108.  
  109.     pop     di                    ; restores registers in popa order
  110.     pop     si
  111.     pop     bp
  112.     pop     bx
  113.     pop     dx
  114.     pop     cx
  115.     pop     ax
  116.  
  117.     iret
  118.  
  119. _tmrisr        ENDP
  120.  
  121.  
  122.  
  123. ;----------------------------------------------------------------------
  124. ; PROCEDURE
  125. ;    SETIVEC  -    install a function as interrupt service routine
  126. ;
  127. ; SYNOPSIS
  128. ;    void setivec(vecno, sizeof(isr), isr)
  129. ;    int vecno;
  130. ;    void (*isr)();
  131. ;
  132. ; PARAMETERS
  133. ;    vecno        -  vector number (0..255)
  134. ;    sizeof(isr)  -  sizeof the function pointer
  135. ;    isr          -  routine to be vectored to
  136. ;
  137. ; REGISTERS
  138. ;    AX, BX, CX, DX
  139. ;
  140. ; REMARKS
  141. ;    Installs isr as an interrupt service routine.  If isr is a
  142. ;    32-bit pointer in segment:offset form, then the specified segment
  143. ;    is used.  If isr contains just the 16-bit offset as indicated by
  144. ;    the sizeof(isr) argument, the current code segment will be assumed
  145. ;    for the segment portion.
  146. ;
  147. ;    Note how interrupts are disabled and restored when writing to the
  148. ;    vector entry by using the flag register.
  149. ;
  150. ; LAST UPDATE
  151. ;    12 February 1988
  152. ;        add sizeof(isr) argument for greater flexibility
  153. ;----------------------------------------------------------------------
  154.  
  155. IF LCODE
  156. _setivec        PROC    FAR
  157. ELSE
  158. _setivec        PROC    NEAR
  159. ENDIF
  160.  
  161.     push    bp
  162.     mov        bp, sp                ; set up stack frame
  163.  
  164.     push    ds                    ; save DS
  165.  
  166.     mov        bx, [bp+AP]            ; get vector number
  167.     shl        bx, 1                ; multiply by 4 to get byte offset
  168.     shl        bx, 1                ;  into interrupt vector table
  169.  
  170.     mov        ax, [bp+AP+4];        ; get offset portion of isr
  171.  
  172.     cmp        WORD PTR [bp+AP+2], 2    ; isr contains 16-bit offset only?
  173.     je        siv_1                ; yes, goto siv_1
  174.  
  175.     mov        dx, [bp+AP+6]        ; isr is 4 bytes, get segment portion
  176.     jmp        siv_2                ; skip over stuff for 2-byte pointers
  177.  
  178. siv_1:                            ; ptr is short, use CS for segment
  179.  
  180.     push    cs
  181.     pop        dx                    ; copy CS into DX
  182.  
  183. siv_2:                            ; prepare to set vector...
  184.  
  185.     xor        cx, cx                ; zero CX to access vector table
  186.  
  187.     pushf                        ; save flags, hence also interrupt status
  188.     cli                            ; disable interrupts - critical section
  189.  
  190.     mov        ds, cx                ; data segment now points to vector table
  191.  
  192.     mov        [bx], ax            ; set isr's offset component
  193.     mov        [bx+2], dx            ; set isr's segment component
  194.  
  195.     popf                        ; restore previous interrupt status
  196.  
  197.     pop        ds                    ; restore DS
  198.  
  199.     pop        bp
  200.     ret
  201.  
  202. _setivec        ENDP
  203.  
  204.  
  205.  
  206. ;----------------------------------------------------------------------
  207. ; FUNCTION
  208. ;    GETIVEC  -  return 32-bit pointer to interrupt service routine
  209. ;
  210. ; SYNOPSIS
  211. ;    long getivec(vecno)
  212. ;    int vecno;
  213. ;
  214. ;    void far *getivec(vecno)
  215. ;    int vecno;
  216. ;
  217. ; PARAMETER
  218. ;    vecno  -  vector number (0..255)
  219. ;
  220. ; RETURNS
  221. ;    segment in DX and offset in AX
  222. ;
  223. ; REGISTERS
  224. ;    AX, BX, DX
  225. ;
  226. ; REMARKS
  227. ;    Two alternative declarations for the return value are possible:
  228. ;    one can declare it as a 32-bit long or a far pointer, depending
  229. ;    on whether your compiler supports Microsoft's far pointer type.
  230. ;
  231. ;    Personally, I prefer a 32-bit long return type since the "far"
  232. ;    keyword is definitely non standard.
  233. ;
  234. ;    It is assumed that the vector entry will not be asynchronously
  235. ;    changed while we are reading it, hence we do not disable interrupts.
  236. ;
  237. ; LAST UPDATE
  238. ;    12 February 1988
  239. ;----------------------------------------------------------------------
  240.  
  241. IF LCODE
  242. _getivec        PROC    FAR
  243. ELSE
  244. _getivec        PROC    NEAR
  245. ENDIF
  246.  
  247.     push    bp
  248.     mov        bp, sp                ; establish stack frame
  249.  
  250.     push    es                    ; save ES
  251.  
  252.     mov        bx, [bp+AP]            ; get vector number
  253.     shl        bx, 1                ; multiply by 4 to get byte offset
  254.     shl        bx, 1                ;  into interrupt vector table
  255.     
  256.     xor        ax, ax                ; zero AX
  257.     mov        es, ax                ; ES now points into vector table
  258.  
  259.     mov        ax, es:[bx]            ; get offset component
  260.     mov        dx, es:[bx+2]        ; get segment component
  261.  
  262.     pop        es
  263.  
  264.     pop        bp
  265.     ret
  266.  
  267. _getivec    ENDP
  268.  
  269.  
  270.  
  271. ;-----------------------------------------------------------------------
  272. ; FUNCTION
  273. ;    ENABLE  -  enable 8086 external interrupt response
  274. ;
  275. ; SYNOPSIS
  276. ;    int enable()
  277. ;
  278. ; RETURNS
  279. ;    1  if interrupts was previously enabled, 0 otherwise
  280. ;
  281. ; LAST UPDATE
  282. ;    9 January 1986
  283. ;-----------------------------------------------------------------------
  284.  
  285. IF LCODE
  286. _enable        PROC    FAR
  287. ELSE
  288. _enable        PROC    NEAR
  289. ENDIF
  290.  
  291.     pushf
  292.     pop        ax                ; get flags for interrupt status
  293.  
  294.     mov        al, ah            ; I flag bit was in AH, now moved to AL
  295.     shr        al, 1            ; shift I flag bit to the bit-0 position
  296.     and        ax, 1            ; mask out all other flag bits
  297.  
  298.     sti                     ; enable CPU interrupt response
  299.  
  300.     ret
  301.  
  302. _enable        ENDP
  303.  
  304.  
  305.  
  306. ;-----------------------------------------------------------------------
  307. ; FUNCTION
  308. ;    DISABLE  -  disable 8086 external interrupt response
  309. ;
  310. ; SYNOPSIS
  311. ;    int disable()
  312. ;
  313. ; RETURNS
  314. ;    1  if interrupts was previously enabled, 0 otherwise
  315. ;
  316. ; LAST UPDATE
  317. ;    9 January 1986
  318. ;-----------------------------------------------------------------------
  319.  
  320. IF LCODE
  321. _disable        PROC    FAR
  322. ELSE
  323. _disable        PROC    NEAR
  324. ENDIF
  325.  
  326.     pushf                    ; get flags and hence interrupt flag bit
  327.  
  328.     cli                        ; disable CPU interrupt response
  329.  
  330.     pop        ax                ; pop flags into AX
  331.  
  332.     mov        al, ah            ; I flag bit was in AH, now moved to AL
  333.     shr        al, 1            ; shift I flag bit to the bit-0 position
  334.     and        ax, 1            ; mask out all other flag bits
  335.  
  336.     ret
  337.  
  338. _disable        ENDP
  339.  
  340.  
  341.  
  342.     INCLUDE epilogue.h
  343.  
  344.     END
  345.  
  346.  
  347.  
  348.