include mc.ash .MODEL SMALL ; ;Time and interrupt functions for IBM hardware. ;set_clk() and reset_clk() enable/disable ;this code from the IBM INT 08 vector. ; ;The built-in counters millisec, second ;and minute increment continually once ;started. ; ; h= set_tick(&timer); ; int h; ; long *timer; ; ; Returns the handle of an allocated ;timer tick; the counter will be continuously ;incremented until the handle is released. ;The timer has a resolution of 1 mS, and ;unknown accuracy. It is generally incremented ;in increments of the system clock. -1 is ;returned if no handles are available. ; ; clr_tick(h); ; int h; ; ; Release a handle. ; .DATA public _millisec,_seconds,_minutes _millisec dd 0 ;milliseconds _seconds dw 0 ;seconds _minutes dw 0 ;and so on ticks dw 0 ;work counter MAXTICK equ 16 ;max. handles pile dw MAXTICK dup (0) ;comma table of .CODE oldvec dd (?) ;saved orig. vector, ; ; h= set_tick(&timer); ; func _set_tick mov cx,MAXTICK mov ax,0 ;AX == handle st1: mov bx,ax shl bx,1 ;word ptr cmp word ptr pile[bx],0 jne st2 ;find a zero, mov dx,arg0 mov pile[bx],dx ;store pointer jmp st3 ;return handle st2: inc ax ;next handle ... loop st1 mov ax,-1 ;no free handles st3: endf _set_tick ; ; clr_tick(h); ; func _clr_tick mov ax,-1 mov bx,arg0 cmp bx,MAXTICK jae ct1 shl bx,1 mov word ptr pile[bx],0 mov ax,0 ct1: endf _clr_tick ; ;Set clock: Insert our routine in series ;with the PCs INT 08h. ; func _set_clk mov al,8 ;vector number, call getvec mov word ptr cs:oldvec,bx ;save it, mov word ptr cs:oldvec + 2,es push ds mov al,8 mov dx,cs ;set for ticker mov ds,dx mov dx,offset ticker call setvec pop ds endf _set_clk ; ;Clear the clock. ; func _clr_clk pushf cli mov ticks,0 ; mov word ptr _millisec,0 ; mov word ptr _millisec + 2,0 mov _seconds,0 mov _minutes,0 popf endf _clr_clk ; ;Remove our timer from the circuit. ; func _reset_clk push ds mov al,8 mov dx,word ptr cs:oldvec mov ds,word ptr cs:oldvec + 2 call setvec pop ds endf _reset_clk page ; ;Ticker routine for the IBM PC, XT, etc etc. ;This generates two time signals: the seconds ;minutes thing, and a millisecond ;timer, which is just a handy thing to have ;around. (And is actually required) ; ticker: push ds push dx push ax mov ax,dgroup mov ds,ax ; ;Do the milliseconds first. Its not really ;milliseconds, since the interrupt is actually ;every 55 mS, but its good enough as a general ;purpose timer. ; mov ax,55 call tickfunc add word ptr _millisec,55 jnc t1 inc word ptr _millisec + 2 ; ;Now we have to coerce seconds amd minutes ;out of the thing. No way we can count ;seconds accurately at 55 mS/tick. ; t1: inc ticks ;ticks/min cmp ticks,1092 ;full min. yet? jb t3 inc _minutes ;yup, next min mov ticks,0 ; ;Now, calculate seconds as accurately as ;possible from the minutes. We count in ;1092nds of a minute, so: ; ;1092 ticks/min= 18.2 ticks/second ; ;A close approximation is: ; ; (N / 16) - (N / 128) ; t3: mov ax,ticks shr ax,1 shr ax,1 shr ax,1 shr ax,1 ; N / 16 mov dx,ax ;save it, shr ax,1 shr ax,1 shr ax,1 ; N / 128, sub dx,ax mov _seconds,dx ; ;Done. Dispatch to the original timer tick, ;that keeps MSDOS time, etc. ; pop ax pop dx pop ds jmp dword ptr cs:[oldvec] ;chain. ; ;Interrupt service routine for ;the timer ticks. AX contains the number ;of milliseconds since the last tick. This ;must preserve all registers. ; tickfunc: push si push bx xor bx,bx tf1: mov si,pile[bx] or si,si jz tf2 add word ptr [si],ax jnc tf2 inc word ptr [si + 2] tf2: add bx,2 cmp bx,(MAXTICK * 2) jb tf1 pop bx pop si ret ; ;Set interrupt vector AL to DS:DX. ; setvec: push es push bx mov bx,0 mov es,bx mov bl,al mov bh,0 shl bx,1 shl bx,1 pushf cli mov es:[bx],dx mov es:[bx + 2],ds popf pop bx pop es ret ; ;Get interupt vector AL, return in ES:BX. ; getvec: push ds push di mov di,0 mov ds,di mov ah,0 mov di,ax shl di,1 shl di,1 pushf cli mov bx,ds:[di] mov es,ds:[di + 2] popf pop di pop ds ret end