
                     (Lightly edited by JRS; not tested)

Date: Tue, 7 Mar 2000 00:51:17 -0500 (EST)
From: robert rozee
To: www.merlyn.demon.co.uk

Hi,

I was reading the page in your site relating to timing under Turbo
Pascal; http://www.merlyn.demon.co.uk/pas-time.htm.  Follows are some
bits of code that might be of interest or that might wish to incorporate
into your page.


procedure restf ;             { restore interrupt flag from stack }
inline(
  $58/           { pop AX        }   { get previously pushed flags }
  $80/$E4/$02/   { and AH,2      }   { check interrupt flag }
  $74/$01/       { jz  short $+3 }   { skip if was not already set }
  $FB);          { sti           }   { enable interrupts }

The above restores from pushf; cli;, as you mention that popf doesn't
restore the interrupt flag under all circumstances.  I had previously
assumed that popf always worked correctly.



function read_count : word ;          { read CTC channel 0 count }
inline(
  $30/$C0/       { xor AL,AL     }
  $9C/           { pushf         }   { save flags status }
  $FA/           { cli           }   { disable interrupts (if enabled) }
  $E6/$43/       { out 43,AL     }   { latch channel 0 count }
  $EB/$00/       { jmp short $+2 }   { delay for slow I/O }
  $E4/$40/       { in  AL,40     }   { get LSB of count }
  $88/$C4/       { mov AH,AL     }   { save in AH }
  $EB/$00/       { jmp short $+2 }   { delay for slow I/O }
  $E4/$40/       { in  AL,40     }   { get MSB of count }
  $59/           { pop CX        }   { get previously pushed flags }
  $80/$E5/$02/   { and CH,2      }   { check interrupt flag }
  $74/$01/       { jz  short $+3 }   { skip if was not already set }
  $FB/           { sti           }   { enable interrupts }
  $86/$C4) ;     { xchg AL,AH    }   { swap LSB&MSB to correct order }

Reads the channel 0 counter.  Only produces useful results if the mode of
the counter has been set to pulse, not square wave.



procedure load_count(count :  word);  { load CTC channel 0 count }
inline(
  $EB/$00/       { jmp shout $+2 }   { delay for slow I/O }
  $E6/$40/       { out 40,AL     }   { load LSB of count }
  $88/$E0/       { mov AL,AH     }
  $EB/$00/       { jmp short $+2 }   { delay for slow I/O }
  $E6/$40) ;     { out 40,AL     }   { load MSB of count }

Puts required jump delays between out instructions. Used thus:
  port[$40] := $36 ;
  load_counter(1193) ;
Recently I've been using this to reprogram the count on-the-fly (without
the port[$40] line!) within the interrupt handler, selecting between
1193 and 1194 divisors to get an exact 1 ms interrupt rate.  I use a
variation on Bresenham's line drawing algorithm to select which divisor
to use.


  ms := ticks*54 ;
  inc(ms, ticks div 2) ;
  inc(ms, ticks div 3) ;
  inc(ms, ticks div 11) ;
  inc(ms, ticks div 798) ;

This is what I use to convert 18.2Hz timer tick counter into
milliseconds.  Seems to work OK, although the values returned are not
going to be 'evenly' spaced.  Any suggestions for a better solution?

{ JRS : yes - *55, Dec div 6 - & others }


{$R-}
var biostime : longint absolute $0040:$006C ;
H, M, S : byte ;
L : longint ;
W : word absolute L ;

begin
  L := biostime ;                   { longint counter at         }
  Dec(L, L div 196629) ;            { 0040h:006Ch which counts   }
  H := L div 65543 ;                { to 1573040 every 24 hours  }
  L := L mod 65543 ;                { is converted to H,M,S by   }
  Dec(L, L div 2849) ;              { subtracting a correction   }
  M := W div 1092 ;                 { based on quotent before    }
  W := W mod 1092 ;                 { main divisions. Note that  }
  Dec(W, W div 90) ;                { L maps over W so that when }
  S := W div 18;                    { L<65536, then W==L.        }
  Writeln(H:4, M:4, S:4) ;
end.

I've been using the above for a _very_ long time to convert timer ticks
into hours/minutes/seconds, although I think I prefer the method given
on your web site.

...


robert rozee, christchurch, new zealand

                                 ----------------
