home *** CD-ROM | disk | FTP | other *** search
-
- /* TIMER - Amiga CIA Timer Control Software
-
- originally by Paul Higginbottom, Public Domain
-
- hacked on by karl to produce a monotonically increasing microsecond
- clock, 12/30/88, Public Domain
-
- second version, released 4/27/89, incorporates changes by Bob (Kodiak)
- Burns, Brian P. Dickson and C. Harald Koch. Specifically, Bob pointed
- out that the hardware manual was wrong and CIA B Timer B was the free
- timer, Brian P. Dickson provided greater accuracy by using 1.396825 for
- the time constant and determining the time constants based on that
- number. Finally, C. Harald Koch found a bug in which the wrong flag
- was used to initialize a control bit, this made it work for CIA A but
- not for CIA B.
-
- cc +p ciatimer.c
- ln ciatimer.o -lcl32
-
- To start the timer, execute BeginCIATimer()
-
- cc +p ciatimer.c
- ln ciatimer.o -lcl32
-
- By providing a solid, high-accuracy realtime clock, this code
- provides a way for timer-releated code that needs to run at
- specific realtimes, like a SMUS player, MIDI sequencer, etc,
- to compensate for delays in their execution caused by interrupts,
- cycle stealing by the blitter, etc.
-
- What you do is keep track of when in realtime you next want to
- run (by adding time intervals to a time returned by ElapsedTime
- when you start, then when you're ready to set up your timer.device
- MICROHZ delay timer, call ElapsedTime and calculate the difference
- in seconds and microseconds as your arguments for your timer.device
- request.
-
- The routine ElapsedTime gets the time by getting the number of
- 55873 microsecond ticks that the handler has seen and retrieving
- the 0-40000 number of 1.396825 microsecond tisks from the CIA timer
- registers, scaling them to 1.000 microsecond ticks and returning
- the shifted-and-or'ed result.
-
- Note that what we really want is an improved timer.device where a
- flag in the timer request could say "schedule me at this microsecond-
- resolution time of day seconds and microseconds" instead of only
- "schedule me in this many seconds and microseconds."
-
- When the CIA interrupt handler is installed, other tasks need a
- way to get the count maintained by the timer routine, too.
-
- This release of the code supports multiple readers.
-
- There is a sample main routine at the end of this program, run the
- program in a window to start this guy as a timer. Control-C within
- the window to get it to exit.
-
- Run the ciafinder program from the CLI in another window and it will
- locate the interrupt data for the timer interrupt maintained by the
- ciatimer task and give you the elapsed time for your time calculation
- in this way.
- */
-
- #include <exec/types.h>
- #include <exec/tasks.h>
- #include <functions.h>
- #include <exec/interrupts.h>
- #include <hardware/cia.h>
- #include <hardware/custom.h>
- #include <hardware/intbits.h>
- #include <resources/cia.h>
- #include <stdio.h>
- #include <libraries/dos.h>
-
- #include "ciatimer.h"
-
- struct CIA_Time CIA_CurrentTime = {0, 0};
-
- static struct Interrupt
- CIATimerInterrupt,
- *OldCIAInterrupt = (struct Interrupt *)-1;
-
- static struct Library *CIAResource = NULL;
-
- #define ciatlo ciab.ciatblo
- #define ciathi ciab.ciatbhi
- #define ciacr ciab.ciacrb
- #define CIAINTBIT CIAICRB_TB
- #define CLEAR 0
-
- void CIAInterrupt()
- {
- CIA_CurrentTime.CIA_Microseconds += CIA_TIME_QUANTITY;
- if (CIA_CurrentTime.CIA_Microseconds > 1000000)
- {
- CIA_CurrentTime.CIA_Seconds++;
- CIA_CurrentTime.CIA_Microseconds -= 1000000;
- }
- }
-
- /* start the timer, clear pending interrupts, and enable timer A
- * Interrupts */
- StartCIATimer()
- {
- ciacr &= ~(CIACRBF_RUNMODE); /* set it to reload on overflow */
- ciacr |= (CIACRBF_LOAD | CIACRBF_START);
- SetICR(CIAResource,CLEAR|CIAICRF_TB);
- AbleICR(CIAResource, CIAICRF_SETCLR | CIAICRF_TB);
- }
-
- void StopCIATimer()
- {
- AbleICR(CIAResource, CLEAR | CIAICRF_TB);
- ciacr &= ~CIACRBF_START;
- }
-
- /* set period between timer increments */
- void SetCIATimer(micros)
- unsigned short micros;
- {
- ciatlo = micros & 0xff;
- ciathi = micros >> 8;
- }
-
- /* stop the timer and remove its interrupt vector */
- EndCIATimer()
- {
- if (OldCIAInterrupt == NULL)
- {
- StopCIATimer();
- RemICRVector(CIAResource, CIAINTBIT, &CIATimerInterrupt);
- }
- }
-
- BOOL BeginCIATimer()
- {
- /* Open the CIA resource */
- if ((CIAResource = (struct Library *)OpenResource(CIABNAME)) == NULL)
- {
- fprintf(stderr,"cia periodic timer startup couldn't open cia resource\n");
- return(0);
- }
-
- CIATimerInterrupt.is_Node.ln_Type = NT_INTERRUPT;
- CIATimerInterrupt.is_Node.ln_Pri = 127;
- CIATimerInterrupt.is_Node.ln_Name = CIATIMER_INTERRUPT_NAME;
- CIATimerInterrupt.is_Code = CIAInterrupt;
- CIATimerInterrupt.is_Data = (APTR)&CIA_CurrentTime;
-
- /* install interrupt */
- if ((OldCIAInterrupt = AddICRVector(CIAResource,CIAINTBIT,&CIATimerInterrupt)) != NULL)
- {
- fprintf(stderr,"cia timer interrupt already in use by '%s'",OldCIAInterrupt->is_Node.ln_Name);
- EndCIATimer();
- return(0);
- }
-
- SetCIATimer(CIA_TIME_SLICE);
-
- StartCIATimer();
- return(TRUE);
- }
-
- main()
- {
- if (BeginCIATimer())
- {
- Wait(SIGBREAKF_CTRL_C);
- }
- else
- exit(1);
-
- EndCIATimer();
- exit(0);
- }
-