home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #30 / NN_1992_30.iso / spool / comp / lang / pascal / 7503 < prev    next >
Encoding:
Text File  |  1992-12-16  |  5.7 KB  |  162 lines

  1. Newsgroups: comp.lang.pascal
  2. Path: sparky!uunet!munnari.oz.au!newsroom.utas.edu.au!pc_100.psychol.utas.edu.au!peter
  3. From: peter@psychnet.psychol.utas.edu.au (Peter R. Tattam)
  4. Subject: Re: High speed clock
  5. Message-ID: <peter.430.724488284@psychnet.psychol.utas.edu.au>
  6. Keywords: clock
  7. Sender: news@newsroom.utas.edu.au
  8. Organization: Psychology Department, University of Tasmania
  9. References: <1992Nov20.091212.24871@lth.se> <peter.422.723796479@psychnet.psychol.utas.edu.au> <Bz47zL.5sH@news.cso.uiuc.edu>
  10. Date: Wed, 16 Dec 1992 06:44:44 GMT
  11. Lines: 149
  12.  
  13. In article <Bz47zL.5sH@news.cso.uiuc.edu> amead@s.psych.uiuc.edu (Alan Mead) writes:
  14. >From: amead@s.psych.uiuc.edu (Alan Mead)
  15. >Subject: Re: High speed clock
  16. >Date: Fri, 11 Dec 1992 22:04:30 GMT
  17. >Keywords: clock
  18.  
  19. >>In article <1992Nov20.091212.24871@lth.se> d92bo@efd.lth.se (Bengt Oehman) writes:
  20. >>From: d92bo@efd.lth.se (Bengt Oehman)
  21. >>Subject: High speed clock
  22. >>Keywords: clock
  23. >>Date: 20 Nov 92 09:12:12 GMT
  24.  
  25.  
  26. >>Does anyone out there know how to do high-speed timing?
  27. >>The internal clock ticks with 18.2 ticks per second, and
  28. >>sometimes this is too slow. I want a resolution of about
  29. >>one millisecond.
  30.  
  31. >>Please reply via email.
  32.  
  33. >I'll reply via email too...
  34.  
  35. >First, a solution:  there is a self-extracting zip file, TIMER.EXE,
  36. >that can be had by anon-ftp from my host, s.psych.uiuc.edu (in /pub I
  37. >think) that incudes a driver that will do this.
  38.  
  39. >Now, can anyone EXPLAIN how this is done?  I have always wanted to
  40. >know--it's really not the best situation to have very OS-specific code
  41. >that you cannot understand and thus maintain.  And, unfortunately, the
  42. >standard in psych is to time events to the millisecond.
  43.  
  44. >Thanks much.
  45.  
  46. >-alan
  47.  
  48. Ok.  I posted something a while back to do it.
  49.  
  50. Basically the idea is to reprogram the timer chip to tick at a different rate. 
  51. You will need some data sheets on how to drive the timer chip... I think 
  52. help-pc has some info in it. The clock normally divides down a 1.193 Mhz clock 
  53. by 65536 (a divisor of 0 which wraps around in 16 bits)  This is where the 
  54. really wierd number of 18.2 comes from.  When they designed the original PC, 
  55. they skimped on the design a bit.  That 1.193 Mhz is derived from the 4.77 Mhz 
  56. master clock.  Pity they didn't choose a more palatable clock frequency, it 
  57. has made the PC an extremely poor timekeeper.
  58.  
  59. What you have to do is change the divisor to some other number.  To 
  60. get 1000 Hz (1 millisecond) you will need a divisor of 1193.  This is accurate 
  61. to 0.1% which is good enough for most purposes, but the inaccuracy builds up 
  62. over time.... for e.g. recording a night's eeg data. 
  63.  
  64. I have experimented with rates down to a divisor of 64 when using the clock to 
  65. generate sound samples on the fly with a 386.   Quite a fun little way to turn 
  66. your pc into a primitive sound processor.
  67.  
  68. Of course changing the default speed will muck up the time as recorded by DOS.
  69. To get around this, I use the following code to check when the clock *would* 
  70. have normally ticked.  I have a counter which has added to it the clock 
  71. divisor every time the interrupt is called.  This counter is a word value so 
  72. every time the counter "wraps around", the carry bit is set.  Now there is no 
  73. mechanism for testing the carry bit in pascal after adding one variable to 
  74. another so one has to resort to a little assembly code to make it happen.  
  75. Here's the critical section.  I have annotated it a little to hopefully 
  76. explain what's going on. 
  77.  
  78. procedure tick_int; assembler;
  79. asm
  80.  
  81.   { save ax and ds }
  82.  
  83.   push ax 
  84.   push ds
  85.  
  86.   { set up our ds }
  87.  
  88.   mov ax,seg @data
  89.   mov ds,ax
  90.  
  91.   { tell the interrupt controller we have finished... 
  92.     this allows next timer interrupt to proceed even when halfway through the 
  93.     timer tick }
  94.  
  95.   mov al,$20
  96.   out $20,al
  97.  
  98.   { increment our millisecond timer }
  99.  
  100.   inc [timer]
  101.  
  102.   { here's the tricky bit.... update our count of 1.193Mhz clocks }
  103.  
  104.   add [clocks],one_msec  { one_msec is a constant defined as 1193 }
  105.   jnc @1
  106.   
  107.   {  our counter overflowed...  call the standard bios clock }
  108.  
  109.   pushf
  110.   call [save_clock]
  111.  
  112. @1:    
  113.   { we are done...  usual return from interrupt }
  114.  
  115.   pop ds
  116.   pop ax
  117.   iret
  118. end;
  119.  
  120.  
  121.  
  122. Now most of this needn't be done as assembly code  (don't flame me even though 
  123. it's in a pascal group, but someone did ask *how* it was done.)  the only 
  124. critical bits would be the "add [clock],one_msec" part and the following 
  125. "pushf/call [save_clock]" pair.  It's impossible to simulate the pushf without 
  126. a lot of hard work.  The check for carry could be simulated by using a longint 
  127. and check for >= 65536 and taking appropriate actions, but the carry method 
  128. will be much safer since the add operation is atomic and the carry is a 
  129. side-effect of the operation.
  130.  
  131. Reprogramming the timer is fairly simple.... just a few port assignments.
  132.  
  133.   port[$43] := $36;
  134.   port[$40] := lo(one_msec);
  135.   port[$40] := hi(one_msec);
  136.  
  137. and when finished return it back to normal.
  138.  
  139.   port[$43] := $36;
  140.   port[$40] := 0;
  141.   port[$40] := 0;
  142.  
  143. Don't bother trying to save the values of the ports.... reading and writing
  144. accesses different registers.
  145.  
  146. All that remains to be done is to save the old interrupt vector, attach the 
  147. routine to our routine, and away you go.
  148.  
  149. I will post the full unit again in another posting.
  150.  
  151. When you've figured all that out, I'll describe a technique I developed which 
  152. allows you to send samples to the pc's speaker by twiddling a couple of timer 
  153. registers.
  154.  
  155. Peter
  156.  
  157. ----------------------------------------------------------------------------
  158. P.Tattam                                    International Phone 61-02-202346
  159. Programmer, Psychology Department           Australia     Phone   002-202346
  160. University of Tasmania, Hobart, Tasmania, Australia
  161. ----------------------------------------------------------------------------
  162.