home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
magazine
/
drdobbs
/
1986
/
03
/
weislst2.mar
< prev
next >
Wrap
Text File
|
1986-03-31
|
9KB
|
235 lines
;---------------------------------------------------;
; Weissman/Dr. Dobbs Submission. Listing 2: ;
; AT timer handler. ;
;---------------------------------------------------;
;---------------------------------------------------;
; Memory-resident handler for the 1024 ;
; tick/sec. realtime clock in the IBM AT: ;
; ;
; Enables INT 70, the clock interrupt, and ;
; counts the ticks at the 1k rate. The range is ;
; 2**32 div 2**10, or 2**22 seconds. Long enough. ;
; ;
; Sets up the usual INT 1A (Get/set time of day) ;
; to handle get/set of the hi-resolution timing ;
; data via special codes in AH register. ;
; ;
; With AH=10h, caller recieves current time in 1k ;
; ticks. ;
; CX returns high 16 bits, DX the low. ;
; AH=11h allows user to set the 32-bit count. ;
; CX=High count to set, DX is low. ;
; ;
; 10/1/85 Written by Gregg Weissman ;
; E-X-E Software Systems ;
; Released to the public domain. ;
;---------------------------------------------------;
CODE segment
assume cs:CODE,ds:CODE,es:CODE,ss:CODE
;-------------------------------------------;
; Conserve memory space: maintain variables ;
; in the unused areas of the program prefix.;
;-------------------------------------------;
org 5ch
I1AJMP dd ? ; Vector to usual 1A int.
I70JMP dd ? ; Ditto the INT 70.
TIMELO dw ? ; low 16 bits of time.
TIMEHI dw ? ; Hi 16 bits of time.
org 100h ; Start of .COM program
BEGIN: jmp short START ; Jump around handlers.
;-------------------------------------------;
; Handle the Get/Set time-of-day INT 1A: ;
; As mentioned, AH=10h Returns time, ;
; AH=11h Sets time ;
; Illegal values >11h return Carry status ;
;-------------------------------------------;
INT_1A proc far
assume ds:nothing,es:nothing,ss:nothing
cmp ah,10h ; See if it's our range of cmnd vals.
jb NOPE_1A ; If less than, assume BIOS int 1a.
sub ah,10h ; Remove special code "bias" of 10h
je GET_TIME ; and branch if equal to "Get" cmnd.
dec ah ; See if "Set" cmns.
jne BAD_CMD_1A ; If not, branch to error.
;-- set time: cx,dx
mov TIMEHI,cx
mov TIMELO,dx
iret
GET_TIME:
mov cx,TIMEHI ; Obtain the number of times the 1024
mov dx,TIMELO ; tick per sec. interrupt has occurred.
iret
BAD_CMD_1A:
stc
ret 2 ; Return an error flag.
NOPE_1A:
jmp I1AJMP ; Continue to BIOS handler via vector.
INT_1A endp
;-------------------------------------------;
; Handle the 1024 ticks/second realtime ;
; clock interrupt: maintain 32-bit count. ;
;-------------------------------------------;
; Still assume ds, etc. nothing in effect. ;
;-------------------------------------------;
INT_70 proc far
push ax
push ds
mov ax,cs
mov ds,ax
assume ds:CODE
inc TIMELO ; Bump low counter.
jne CONT_70 ; Continue if count not wrapped around
inc TIMEHI ; Bump high counter.
CONT_70:
pushf ; Simulate INT nn
call I70JMP ; Call the realtime clock handler,
; to let BIOS handle user-event-wait.
call ENABLE_INT ; And return here so we can re-init
pop ds ; the timer: BIOS turns it off.
pop ax
iret
INT_70 endp
;-----------------------------------------;
; This routine enables the "PIE", or ;
; periodic interrupt event. It is called ;
; when the system initializes, and after ;
; each tick, in case BIOS turned it off. ;
;-----------------------------------------;
; This communicates with the CMOS ;
; module via ports 70h & 71h. The ;
; "JMP $+2" is for a delay between ;
; port accesses, allowing the device ;
; time to settle down. The 80286 is ;
; too fast. ;
;-----------------------------------------;
ENABLE_INT proc near
cli ; Prevent interruption.
mov al,0bh ; First, identify the reg.
out 70h,al ; we want (0b is the one).
jmp $+2 ; Just a long NOP.
in al,71h
or al,01000000b ; This bit is int. enable
mov ah,al ; Save value: we need al
mov al,0bh ; Address the register again.
out 70h,al
jmp $+2 ; NOP
mov al,ah ; Get back the desired value.
out 71h,al ; Now stored in CMOS & ready.
in al,0a1h ; Int. control chip register.
and al,0feh ; Bit 0 is another int. enable
out 0a1h,al ; now set to allow interrupt.
mov al,20h ; Send "End of interrupt" for
out 0a0h,al ; good measure.
out 020h,al ; ditto controller chip 1.
sti
ret
ENABLE_INT endp
;-------------------------------------------;
; Initialize the interrupt handlers and ;
; the interrupt generator itself. Leave ;
; behind the resident code. ;
;-------------------------------------------;
; We leave out amenities like DOS version ;
; test and check for an actual AT. ;
;-------------------------------------------;
START:
assume ds:CODE,es:CODE,ss:CODE
mov ah,10h ; First check to see if already
clc ; resident,
mov cx,1234h ; by constructing an unlikely
mov dx,cx ; time value of 12341234h
int 1ah ; See if we get the time back.
cmp cx,dx ; If cx=1234=dx, not present.
je NOT_THERE
mov dx,offset ALREADY ; Tell the user it's in already
mov ah,9 ; using DOS print function.
int 21h
mov ax,4c01h ; Terminate with errorlevel 1
int 21h
NOT_THERE:
mov ax,3570h ; Get the current vectors
int 21h ; from DOS.
mov word ptr I70JMP,bx ; Save in prefix are variables.
mov word ptr I70JMP+2,es
mov ax,351ah ; Got the 70, now get 1A
int 21h
mov word ptr I1AJMP,bx
mov word ptr I1AJMP+2,es
push cs ; Restore es for form's sake
pop es
mov THIS_SEG,cs
cli
mov dx,offset INT_1a ; Set interrupt vectors to our handlers
mov ax,251ah
int 21h
mov dx,offset INT_70 ; Ditto for int 70.
mov ax,2570h
int 21h
mov dx,offset HELLO ; Print a message
mov ah,9
int 21h
call ENABLE_INT ; Start the timer.
mov dx,offset START+15 ; Set terminate address in
mov cl,4 ; paragraphs, rounding up &
shr dx,cl ; dividing by 16.
mov TIMELO,0 ; Clear the current time.
mov TIMEHI,0
mov ax,3100h ; Terminate & stay put.
int 21h ; End.
;-- Messages for the user:
HELLO db 'Hi-resolution AT timer now loaded.',13,10,'$'
ALREADY db 'The resident timer handler is already installed.',13,10,'$'
CODE ends
end BEGIN