; \sources\tomlib\mikro.asm  17.mai.87 tom
;
; routinen fuer precise zeitmessung auf PC/AT (quelle && idee BYTE 1'87 S.157)
; precision ca. +- 2 musec
;
; long ticks_abs()  : gebe anzahl von ticks absolute zurueck
;                   : Einheit 838.096 nanosekunden
; long mikro_abs()  : gebe absolute zeit in mikrosekunden zurueck
; long mikro_since(): gebe zeit seit letztem aufruf von mikro_since()
;                   : oder mikro_diff() zurueck
; long mikro_diff() : wie mikro_since(), aber um die aufrufzeit von
;                   : mikrodiff selbst bereinigt.
;                   : i.e.
;                   :       mikro_diff();
;                   :       i = i+1;
;                   :       time = mikro_diff();
;                   : ergibt exact die zeit fuer "i = i+1;"
;
;
    NAME    MIKRO

include tomlib.equ

timer_low       = 006ch
bios_dataseg    = 0040h
timer_mode      = 43h
timer0          = 40h
multconst       = 54925     ; counts in musec verwandeln


_DATA SEGMENT
lastticklow  dw 0
lasttickhigh dw 0
bios_timer_low_ptr dw timer_low,bios_dataseg

diffmikrosec dw 0
init_label  dw offset _mikro_init
_DATA ends



textsegment

    public _mikro_since,_mikro_diff,_mikro_abs,_ticks_abs,_mikro_init



_MIKRO proc near


_mikro_init:
;
;  initialize timer for software analysis
;  kann wiederholt aufgerufen werden, initialisiert nur beim ersten mal
;

        mov     word ptr init_label,offset noinit_lab

        mov     al,00110100b    ; initialize right mode for counting
        out     timer_mode,al

        xor     ax,ax
        out     timer0,al
        push    ax              ; Dummy : OUT nicht ueberfordern
        pop     ax
        out     timer0,al

        mov     diffmikrosec,0  ; see what time we get if no correction done
        localcall _mikro_diff     ; initialize mikro_diff
        localcall _mikro_diff     ;
        mov     diffmikrosec,ax ; and store this into correction value

ticks_abs:
        jmp    word ptr init_label

noinit_lab:

        les     bx,dword ptr bios_timer_low_ptr
retry_ticks:
        sub     al,al
        mov     dx,es:[bx]      ; dx contains BIOS-maintained count

        pushf
        cli
        out     timer_mode,al   ; read ticks now
        in      al,timer0
        mov     ah,al
        jmp short l3
l3:     in      al,timer0
        popf

        xchg    ah,al           ; ax contains count from timer
        neg     ax
        cmp     dx,es:[bx]      ; dx contains BIOS-maintained count
		jne retry_ticks ; interrupt occured

        ret


_MIKRO  endp

procedure _MIKRO1

_mikro_since:

        call    ticks_abs      ; get ticks to ax,dx
        mov     bx,ax           ; duplicate
        mov     cx,dx
        xchg    bx,lastticklow
        xchg    dx,lasttickhigh
        sub     ax,bx           ; time = -(actticks - lastticks)
        sbb     cx,dx           ; in ax:cx

convert_to_musec:
        mov     bx,multconst    ; make musec from ticks
        mul     bx              ; mikroseconds now in dx
        mov     ax,cx           ; high part of ticks
        mov     cx,dx           ; save musecs
        mul     bx              ; dx:ax = musecs from ticks
        add     ax,cx           ; add musecs from count
        adc     dx,0            ; add carry

        ret                     ; that's it

_mikro_abs:
        call    ticks_abs
        mov     cx,dx
        jmp     convert_to_musec

_mikro_diff:
        localcall    _mikro_since        ; get mikroseconds
        sub     ax,diffmikrosec     ; and correct for routine overhead
        sbb     dx,0
        ret

_ticks_abs:
	call  ticks_abs
	ret

_MIKRO1  endp

TEXTEND

    END
