home *** CD-ROM | disk | FTP | other *** search
- ;***********************************************************************
- ;
- ; FILE
- ; timeinta.asm - timer interrupt demo, assembly portion
- ;
- ; REMARKS
- ; This module implements some of the very basic functions needed
- ; to set up a timer interrupt service routine.
- ;
- ; The C language service routine MUST be named tick() and the
- ; low level interrupt handler is named here as tmrisr().
- ;
- ; Note that this module is designed to be used with Microsoft C
- ; version 4.00 and above; it will probably work with version 3.00
- ; also. All global names are preceeded by an underscore and you
- ; must assemble using the /ml flag to preserve case sensitivity:
- ;
- ; masm timeinta /ml;
- ;
- ; LAST UPDATE
- ; 15 January 1988 by Haam
- ; special version to demo how to roll your own timer isr
- ;
- ; Copyright(c) 1986-1988 D.M. Auslander and C.H. Tham
- ;
- ;***********************************************************************
-
- EOIPORT EQU 20h ; where to send the EOI byte
- SEOI EQU 60h ; specific EOI byte for the timer
-
- INCLUDE model.h ; memory model definitions
-
- IF LCODE
- EXTRN _tick:FAR ; tick is in different code segment
- ENDIF
-
- INCLUDE prologue.h ; setup stuff
-
- IFE LCODE
- EXTRN _tick:NEAR ; tick is in same code segment
- ENDIF
-
-
- PUBLIC _tmrisr ; this means tmrisr() is visible
-
- PUBLIC _setivec, _getivec
- PUBLIC _enable, _disable
-
-
-
- ;----------------------------------------------------------------------
- ; PROCEDURE
- ; TMRISR - timer interrupt service routine
- ;
- ; SYNOPSIS
- ; void tmrisr(void), vectored to by timer interrupt
- ;
- ; REMARKS
- ; Saves the registers and switch to the program's data segment which
- ; is defined by DGROUP in all memory models. The CPU's interrupt
- ; response is enabled with a sti instruction almost immediately to
- ; allow higher priority interrupts to interrupt this interrupt, not
- ; that it makes much difference in the IBM-PC since the timer is the
- ; highest priority interrupt.
- ;
- ; A specific EOI (end-of-interrupt) byte is sent to the 8259 Interrupt
- ; Controller at the end of the service function, tick(). This tells
- ; the 8259 that we are done servicing the timer interrupt. Without
- ; an EOI notification, the 8259 will not allow another timer interrupt
- ; (plus all lower priority interrupts) to be passed to the CPU.
- ;
- ; There are ways around this, for example, by using the special mask
- ; mode, but that is beyond the scope of this exercise.
- ;
- ; LAST UPDATE
- ; 10 January 1988
- ;----------------------------------------------------------------------
-
- IF LCODE
- _tmrisr PROC FAR
- ELSE
- _tmrisr PROC NEAR
- ENDIF
-
- sti ; enable CPU's interrupt response
-
- push ax ; save registers in pusha order
- push cx
- push dx
- push bx
- push bp
- push si
- push di
-
- push ds ; save data and extra segments
- push es
-
- mov ax, SEG DGROUP ; switch to program's data segment
- mov ds, ax
-
- call _tick
-
- mov al, SEOI ; send specific EOI
- out EOIPORT, al
-
- pop es ; restores data and extra segments
- pop ds
-
- pop di ; restores registers in popa order
- pop si
- pop bp
- pop bx
- pop dx
- pop cx
- pop ax
-
- iret
-
- _tmrisr ENDP
-
-
-
- ;----------------------------------------------------------------------
- ; PROCEDURE
- ; SETIVEC - install a function as interrupt service routine
- ;
- ; SYNOPSIS
- ; void setivec(vecno, sizeof(isr), isr)
- ; int vecno;
- ; void (*isr)();
- ;
- ; PARAMETERS
- ; vecno - vector number (0..255)
- ; sizeof(isr) - sizeof the function pointer
- ; isr - routine to be vectored to
- ;
- ; REGISTERS
- ; AX, BX, CX, DX
- ;
- ; REMARKS
- ; Installs isr as an interrupt service routine. If isr is a
- ; 32-bit pointer in segment:offset form, then the specified segment
- ; is used. If isr contains just the 16-bit offset as indicated by
- ; the sizeof(isr) argument, the current code segment will be assumed
- ; for the segment portion.
- ;
- ; Note how interrupts are disabled and restored when writing to the
- ; vector entry by using the flag register.
- ;
- ; LAST UPDATE
- ; 12 February 1988
- ; add sizeof(isr) argument for greater flexibility
- ;----------------------------------------------------------------------
-
- IF LCODE
- _setivec PROC FAR
- ELSE
- _setivec PROC NEAR
- ENDIF
-
- push bp
- mov bp, sp ; set up stack frame
-
- push ds ; save DS
-
- mov bx, [bp+AP] ; get vector number
- shl bx, 1 ; multiply by 4 to get byte offset
- shl bx, 1 ; into interrupt vector table
-
- mov ax, [bp+AP+4]; ; get offset portion of isr
-
- cmp WORD PTR [bp+AP+2], 2 ; isr contains 16-bit offset only?
- je siv_1 ; yes, goto siv_1
-
- mov dx, [bp+AP+6] ; isr is 4 bytes, get segment portion
- jmp siv_2 ; skip over stuff for 2-byte pointers
-
- siv_1: ; ptr is short, use CS for segment
-
- push cs
- pop dx ; copy CS into DX
-
- siv_2: ; prepare to set vector...
-
- xor cx, cx ; zero CX to access vector table
-
- pushf ; save flags, hence also interrupt status
- cli ; disable interrupts - critical section
-
- mov ds, cx ; data segment now points to vector table
-
- mov [bx], ax ; set isr's offset component
- mov [bx+2], dx ; set isr's segment component
-
- popf ; restore previous interrupt status
-
- pop ds ; restore DS
-
- pop bp
- ret
-
- _setivec ENDP
-
-
-
- ;----------------------------------------------------------------------
- ; FUNCTION
- ; GETIVEC - return 32-bit pointer to interrupt service routine
- ;
- ; SYNOPSIS
- ; long getivec(vecno)
- ; int vecno;
- ;
- ; void far *getivec(vecno)
- ; int vecno;
- ;
- ; PARAMETER
- ; vecno - vector number (0..255)
- ;
- ; RETURNS
- ; segment in DX and offset in AX
- ;
- ; REGISTERS
- ; AX, BX, DX
- ;
- ; REMARKS
- ; Two alternative declarations for the return value are possible:
- ; one can declare it as a 32-bit long or a far pointer, depending
- ; on whether your compiler supports Microsoft's far pointer type.
- ;
- ; Personally, I prefer a 32-bit long return type since the "far"
- ; keyword is definitely non standard.
- ;
- ; It is assumed that the vector entry will not be asynchronously
- ; changed while we are reading it, hence we do not disable interrupts.
- ;
- ; LAST UPDATE
- ; 12 February 1988
- ;----------------------------------------------------------------------
-
- IF LCODE
- _getivec PROC FAR
- ELSE
- _getivec PROC NEAR
- ENDIF
-
- push bp
- mov bp, sp ; establish stack frame
-
- push es ; save ES
-
- mov bx, [bp+AP] ; get vector number
- shl bx, 1 ; multiply by 4 to get byte offset
- shl bx, 1 ; into interrupt vector table
-
- xor ax, ax ; zero AX
- mov es, ax ; ES now points into vector table
-
- mov ax, es:[bx] ; get offset component
- mov dx, es:[bx+2] ; get segment component
-
- pop es
-
- pop bp
- ret
-
- _getivec ENDP
-
-
-
- ;-----------------------------------------------------------------------
- ; FUNCTION
- ; ENABLE - enable 8086 external interrupt response
- ;
- ; SYNOPSIS
- ; int enable()
- ;
- ; RETURNS
- ; 1 if interrupts was previously enabled, 0 otherwise
- ;
- ; LAST UPDATE
- ; 9 January 1986
- ;-----------------------------------------------------------------------
-
- IF LCODE
- _enable PROC FAR
- ELSE
- _enable PROC NEAR
- ENDIF
-
- pushf
- pop ax ; get flags for interrupt status
-
- mov al, ah ; I flag bit was in AH, now moved to AL
- shr al, 1 ; shift I flag bit to the bit-0 position
- and ax, 1 ; mask out all other flag bits
-
- sti ; enable CPU interrupt response
-
- ret
-
- _enable ENDP
-
-
-
- ;-----------------------------------------------------------------------
- ; FUNCTION
- ; DISABLE - disable 8086 external interrupt response
- ;
- ; SYNOPSIS
- ; int disable()
- ;
- ; RETURNS
- ; 1 if interrupts was previously enabled, 0 otherwise
- ;
- ; LAST UPDATE
- ; 9 January 1986
- ;-----------------------------------------------------------------------
-
- IF LCODE
- _disable PROC FAR
- ELSE
- _disable PROC NEAR
- ENDIF
-
- pushf ; get flags and hence interrupt flag bit
-
- cli ; disable CPU interrupt response
-
- pop ax ; pop flags into AX
-
- mov al, ah ; I flag bit was in AH, now moved to AL
- shr al, 1 ; shift I flag bit to the bit-0 position
- and ax, 1 ; mask out all other flag bits
-
- ret
-
- _disable ENDP
-
-
-
- INCLUDE epilogue.h
-
- END
-
-
-