home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / alib / d1xx / d178 / ciatimer.lha / CIATimer / ciatimer.c < prev    next >
C/C++ Source or Header  |  1989-02-04  |  8KB  |  282 lines

  1. /* TIMER - Amiga CIA Timer Control Software
  2.  
  3.   originally by Paul Higginbottom, Public Domain, published in AmigaMail
  4.  
  5.   hacked on by Karl Lehenbauer to produce a monotonically increasing 
  6.   microsecond clock, 12/30/88. All changes are Public Domain.
  7.  
  8.   cc +p ciatimer.c
  9.   ln ciatimer.o -lcl32
  10.  
  11.     By providing a solid, high-accuracy realtime clock, this code
  12.     provides a way for timer-releated code that needs to run at
  13.     specific realtimes, like a SMUS player, MIDI sequencer, etc,
  14.     to compensate for delays in their execution caused by interrupts,
  15.     cycle stealing by the blitter, etc.
  16.  
  17.     What you do is keep track of when in realtime you next want to 
  18.     run (by adding time intervals to a time returned by ElapsedTime
  19.     when you start, then when you're ready to set up your timer.device
  20.     MICROHZ delay timer, call ElapsedTime and calculate the difference 
  21.     in seconds and microseconds as your arguments for your timer.device
  22.     request.
  23.  
  24.     The routine ElapsedTime gets the time by getting the number of
  25.     65536 microsecond ticks that the handler has seen and retrieving
  26.     the 0-46911 number of 1.397 microsecond ticks from the CIA timer
  27.     registers, scaling them to 1.000 microsecond ticks and returning
  28.     the shifted-and-ored result.
  29.  
  30.     A couple routines at the bottom of the file that're commented out 
  31.     are from my SMUS player and demonstrate how to perform the time 
  32.     arithmetic as described above.
  33.  
  34.     Note that what we really want is an improved timer.device where a
  35.     flag in the timer request could say  "schedule me at this microsecond-
  36.     resolution time of day seconds and microseconds" instead of only
  37.     "schedule me in this many seconds and microseconds."
  38.  
  39.     When the CIA interrupt handler is installed, other tasks need a
  40.     way to get the count maintained by the timer routine, too.
  41.     I was thinking maybe a library could be used and, by opening it,
  42.     tasks could get to the address of the long word that the interrupt
  43.     handler increments every time it runs.
  44. */
  45.  
  46. #include <exec/types.h>
  47. #include <exec/tasks.h>
  48. #include <functions.h>
  49. #include <exec/interrupts.h>
  50. #include <hardware/cia.h>
  51. #include <hardware/custom.h>
  52. #include <hardware/intbits.h>
  53. #include <resources/cia.h>
  54. #include <stdio.h>
  55.  
  56. long CIA_Seconds = 0;    
  57. long CIA_Microseconds = 0;
  58.  
  59. /* timeslice is 46911 intervals.  Each interval is 1.397 microseconds,
  60.  * this should correspond to a timing interval of 65536 microseconds */
  61. #define CIA_TIME_SLICE ((unsigned short) 46911)
  62.  
  63. static struct Interrupt
  64.    CIATimerInterrupt,
  65.    *OldCIAInterrupt = (struct Interrupt *)-1;
  66.  
  67. static struct Library *CIAResource = NULL;
  68.  
  69. #define ciatlo ciaa.ciatalo
  70. #define ciathi ciaa.ciatahi
  71. #define ciacr ciaa.ciacra
  72. #define CIAINTBIT CIAICRB_TA
  73. #define CLEAR 0
  74.  
  75. panic(s)
  76. char *s;
  77. {
  78.     fflush(stdout);
  79.     fprintf(stderr,"panic: %s\n",s);
  80.     fflush(stderr);
  81.     EndCIATimer();
  82. }
  83.  
  84. /* this is the actual interrupt routine.  since +p 32-bit model is used,
  85.  * no special dinking around is necessary to get a C routine to run as
  86.  * an interrupt.
  87.  */
  88. VOID CIAInterrupt()
  89. {
  90.     /* increment saved microseconds by number generated between CIA
  91.      * interrupts, and if we passed a million, increment seconds */
  92.     CIA_Microseconds += 65536;
  93.     if (CIA_Microseconds > 1000000)
  94.     {
  95.         CIA_Seconds++;
  96.         CIA_Microseconds -= 1000000;
  97.     }
  98. }
  99.  
  100. /* start the timer, clear pending interrupts, and enable timer A
  101.  * Interrupts */
  102. StartCIATimer()
  103. {
  104.     ciacr &= ~(CIACRAF_RUNMODE);    /* set it to reload on overflow */
  105.     ciacr |= (CIACRAF_LOAD | CIAICRF_TA);
  106.     SetICR(CIAResource,CLEAR|CIAICRF_TA);
  107.     AbleICR(CIAResource, CIAICRF_SETCLR | CIAICRF_TA);
  108. }
  109.  
  110. void StopCIATimer()
  111. {
  112.     AbleICR(CIAResource, CLEAR | CIAICRF_TA);
  113.     ciacr &= ~CIACRAF_START;
  114. }
  115.  
  116. /* set period between timer increments */
  117. void SetCIATimer(micros)
  118. unsigned short micros;
  119. {
  120.     ciatlo = micros & 0xff;
  121.     ciathi = micros >> 8;
  122. }
  123.  
  124. /* stop the timer and remove its interrupt vector */
  125. EndCIATimer()
  126. {
  127.     if (OldCIAInterrupt == NULL)
  128.     {
  129.         StopCIATimer();
  130.         RemICRVector(CIAResource, CIAINTBIT, &CIATimerInterrupt);
  131.     }
  132. }
  133.  
  134. BOOL BeginCIATimer()
  135. {
  136.     /* Open the CIA resource */
  137.     if ((CIAResource = (struct Library *)OpenResource(CIAANAME)) == NULL)
  138.         panic("timer couldn't open cia resource");
  139.  
  140.     CIATimerInterrupt.is_Node.ln_Type = NT_INTERRUPT;
  141.     CIATimerInterrupt.is_Node.ln_Pri = 127;
  142.     CIATimerInterrupt.is_Code = CIAInterrupt;
  143.  
  144.     /* install interrupt */
  145.     if ((OldCIAInterrupt = AddICRVector(CIAResource,CIAINTBIT,&CIATimerInterrupt)) != NULL)
  146.         panic("cia timer interrupt already in use.");
  147.  
  148.     SetCIATimer(CIA_TIME_SLICE);
  149.  
  150.     StartCIATimer();
  151.     return(TRUE);
  152. }
  153.  
  154. /* return the elapsed real time in seconds and microseconds since the
  155.  * cia timer interrupt handler was installed.
  156.  *
  157.  * ElapsedTime(&secs,µsecs);
  158.  *
  159.  * with the chosen timeslice interval, every timer interrupt represents
  160.  * 65536 microseconds, so the count of interrupts received can be shifted
  161.  * and or'ed in.  The thing that needs scaling is the timer count we
  162.  * read from the hardware registers.  It's range of 0 - 46911 1.397
  163.  * microsecond ticks must be changed to a range of 0 - 65535 1.0 
  164.  * microsecond ticks, which is done below
  165.  *
  166.  * note the code should really read the lo count register again after
  167.  * reading the high one and comparing them to be sure it didn't wrap
  168.  * in between reads
  169.  *
  170.  * interrupts are off during this to reduce the possibility of a problem
  171.  * with the counter interrupt coming between the cia reads and the big tick
  172.  * read, and because it's short it's no biggie, but again it should 
  173.  * really do more
  174.  */
  175. void ElapsedTime(sec_ptr,usec_ptr)
  176. int *sec_ptr,*usec_ptr;
  177. {
  178.     register long seconds, microseconds;
  179.     register long ciahi, cialo;
  180.  
  181.     Disable();
  182.     ciahi = ciathi;
  183.     cialo = ciatlo;
  184.     seconds = CIA_Seconds;
  185.     microseconds = CIA_Microseconds;
  186.     Enable();
  187.     /* total microseconds is CIA_BigTicks * 65536 + timerval * 1.397 */
  188.     /* to multiply the timer ticks * 1.397, you can multiply by 1430
  189.      * and divide by 1024 (or shift right by 10, get it?) 
  190.      */
  191.     ciahi = CIA_TIME_SLICE - ((ciahi << 8) + cialo);
  192.     ciahi = ((ciahi * 1430) >> 10) & 0xffff;
  193.  
  194.     microseconds += ciahi;
  195.     if (microseconds > 1000000)
  196.     {
  197.         microseconds -= 1000000;
  198.         seconds++;
  199.     }
  200.  
  201.     *sec_ptr = seconds;
  202.     *usec_ptr = microseconds;
  203.     return;
  204. }
  205.  
  206. /* this is a demo routine */
  207. main()
  208. {
  209.     long secs, microsecs;
  210.  
  211.     printf("CIA Timer Demo\n\n");
  212.     printf("Every time getchar() succeeds, I'll print seconds and microseconds\n");
  213.     printf("elapsed since I installed a CIA timer interrupt handler.\n\n");
  214.     printf("So hit return to get the message, control-backslash to exit.\n");
  215.     printf("Type some chars and hit return to get it a bunch of times really fast.\n\n");
  216.  
  217.     printf("This demonstrates using a CIA timer in loop mode to derive\n");
  218.     printf("a monotonically increasing microsecond-resolution clock.\n\n");
  219.  
  220.     BeginCIATimer();
  221.  
  222.     while (getchar() > 0)
  223.     {
  224.         ElapsedTime(&secs,µsecs);
  225.         printf("ET %d secs, %d microsecs\n",secs,microsecs);
  226.     }
  227.  
  228.     EndCIATimer();
  229. }
  230.  
  231. /*
  232. long reference_seconds, reference_microseconds;
  233.  
  234. void set_wait_ticks(delay_ticks)
  235. long delay_ticks;
  236. {
  237.     register long desired_seconds, desired_microseconds;
  238.     long current_seconds,current_microseconds;
  239.  
  240.     timer_request->tr_node.io_Command = TR_ADDREQUEST;
  241.  
  242.     reference_microseconds += microseconds_per_tick * delay_ticks;
  243.  
  244.     while (reference_microseconds >= 1000000)
  245.     {
  246.         reference_microseconds -= 1000000;
  247.         reference_seconds++;
  248.     }
  249.  
  250.     ElapsedTime(¤t_seconds,¤t_microseconds);
  251.     desired_seconds = reference_seconds - current_seconds;
  252.     desired_microseconds = reference_microseconds - current_microseconds;
  253.  
  254.     if (desired_microseconds < 0)
  255.     {
  256.         desired_microseconds += 1000000;
  257.         desired_seconds--;
  258.     }
  259.  
  260.     if (desired_seconds >= 0)
  261.     {
  262.         timer_request->tr_time.tv_secs = desired_seconds;
  263.         timer_request->tr_time.tv_micro = desired_microseconds;
  264.     }
  265.     else
  266.     {
  267.         timer_request->tr_time.tv_secs = 0;
  268.         timer_request->tr_time.tv_micro = 1;
  269.     }
  270.     SendIO(timer_request);
  271. }
  272.  
  273. SetReferenceTime()
  274. {
  275.     ElapsedTime(&reference_seconds,&reference_microseconds);
  276. }
  277.  
  278. */
  279.  
  280.  
  281.  
  282.