[comp.sys.amiga.tech] New periodic timing routines -- multiple tasks can now share

karl@sugar.uu.net (Karl Lehenbauer) (01/10/89)

Below is a shar of my latest version of Paul Higginbottom's CIA timer
routines.  What's cool about this version is tasks can call a function
LocateTimerData, which locates the interrupt's is_Data area, hence
multiple tasks can use the same CIA timer to get a microsecond-resolution
realtime clock.  To check out the demo, compile it up, start 'ciatimer' then 
run 'ciafinder' anytime afterwards to see the elapsed seconds and microseconds
since starting ciatimer.  Ciatimer will remove the interrupt, clean up and
exit if it gets a control-C in its CLI.

The reason I didn't send this to the sources group is that it's not really big
and it's still really beta.  Flame me in mail or something if you think it's
inappropriate. -k

:
#! /bin/sh
# This is a shell archive, created on Sugar Land Unix (..!uunet!sugar)
# (bbs: 713-438-5018) by karl (Karl Lehenbauer) on Mon Jan  9 19:51:56 1989
# Remove anything before the "#! /bin/sh" line, then unpack it by saving
# it into a file and typing "sh file".  If you do not have sh, you need 
# unshar, a dearchiving program which is widely available.  In the absolute
# wost case, you can crack the files out by hand.
# If the archive is complete, you will see the message "End of archive."
# at the end.
# This archive contains the following files...
# 'ciatimer.h'
# 'ciatimer.c'
# 'ciafinder.c'
# To extract them, run the following through /bin/sh
echo x - ciatimer.h
sed 's/^X//' > ciatimer.h << '//END_OF_FILE'
X/* ciatimer.h - include file Amiga CIA Timer Control Software 0.1a
X
X  CIA timer code originally by Paul Higginbottom, Public Domain
X
X  this include file was written by Karl Lehenbauer, Public Domain
X
X  cc +p ciatimer.c
X  ln ciatimer.o -lcl32
X
X  To start the timer, execute BeginCIATimer()
X
X*/
X
Xstruct CIA_Time
X{
X	long CIA_Seconds;
X	long CIA_Microseconds;
X};
X
X/* timeslice is 46911 intervals.  Each interval is 1.397 microseconds,
X * this should correspond to a timing interval of 65536 microseconds */
X#define CIA_TIME_SLICE ((unsigned short) 46911)
X
X#define CIATIMER_INTERRUPT_NAME "CIA Periodic Timer"
X
//END_OF_FILE
echo x - ciatimer.c
sed 's/^X//' > ciatimer.c << '//END_OF_FILE'
X/* TIMER - Amiga CIA Timer Control Software 0.1a
X
X  originally by Paul Higginbottom, Public Domain
X
X  hacked on by Karl Lehenbauer to produce a monotonically increasing microsecond
X  clock, 12/30/88, Public Domain
X
X  further hacking by Karl to provide arbitrary tasks the ability to locate
X  the CIA interrupt's time data, 1/5/88, Public Domain
X
X  cc +p ciatimer.c
X  ln ciatimer.o -lcl32
X
XTo start up the timer, execute ciatimer.  To kill it, control-C.  The task
Xdoesn't do anything except wait for the control-C and clean up afterwards,
Xremoving the interrupt.
X
Xciafinder may then be used to locate the is_Data section of ciatimer's
Xinterrupt, where ciatimer writes its time data.
X*/
X
X#include <exec/types.h>
X#include <exec/tasks.h>
X#include <functions.h>
X#include <exec/interrupts.h>
X#include <hardware/cia.h>
X#include <hardware/custom.h>
X#include <hardware/intbits.h>
X#include <resources/cia.h>
X#include <stdio.h>
X#include <libraries/dos.h>
X
X#include "ciatimer.h"
X
Xstruct CIA_Time CIA_CurrentTime = {0, 0};
X
Xstatic struct Interrupt
X   CIATimerInterrupt,
X   *OldCIAInterrupt = (struct Interrupt *)-1;
X
Xstatic struct Library *CIAResource = NULL;
X
X#define ciatlo ciaa.ciatalo
X#define ciathi ciaa.ciatahi
X#define ciacr ciaa.ciacra
X#define CIAINTBIT CIAICRB_TA
X#define CLEAR 0
X
Xvoid CIAInterrupt()
X{
X	CIA_CurrentTime.CIA_Microseconds += 65536;
X	if (CIA_CurrentTime.CIA_Microseconds > 1000000)
X	{
X		CIA_CurrentTime.CIA_Seconds++;
X		CIA_CurrentTime.CIA_Microseconds -= 1000000;
X	}
X}
X
X/* start the timer, clear pending interrupts, and enable timer A
X * Interrupts */
XStartCIATimer()
X{
X	ciacr &= ~(CIACRAF_RUNMODE);	/* set it to reload on overflow */
X	ciacr |= (CIACRAF_LOAD | CIAICRF_TA);
X	SetICR(CIAResource,CLEAR|CIAICRF_TA);
X	AbleICR(CIAResource, CIAICRF_SETCLR | CIAICRF_TA);
X}
X
Xvoid StopCIATimer()
X{
X	AbleICR(CIAResource, CLEAR | CIAICRF_TA);
X	ciacr &= ~CIACRAF_START;
X}
X
X/* set period between timer increments */
Xvoid SetCIATimer(micros)
Xunsigned short micros;
X{
X	ciatlo = micros & 0xff;
X	ciathi = micros >> 8;
X}
X
X/* stop the timer and remove its interrupt vector */
XEndCIATimer()
X{
X	if (OldCIAInterrupt == NULL)
X	{
X		StopCIATimer();
X		RemICRVector(CIAResource, CIAINTBIT, &CIATimerInterrupt);
X	}
X}
X
XBOOL BeginCIATimer()
X{
X	/* Open the CIA resource */
X	if ((CIAResource = (struct Library *)OpenResource(CIAANAME)) == NULL)
X	{
X		fprintf(stderr,"cia periodic timer startup couldn't open cia resource\n");
X		return(0);
X	}
X
X	CIATimerInterrupt.is_Node.ln_Type = NT_INTERRUPT;
X	CIATimerInterrupt.is_Node.ln_Pri = 127;
X	CIATimerInterrupt.is_Node.ln_Name =  CIATIMER_INTERRUPT_NAME;
X	CIATimerInterrupt.is_Code = CIAInterrupt;
X	CIATimerInterrupt.is_Data = (APTR)&CIA_CurrentTime;
X
X	/* install interrupt */
X	if ((OldCIAInterrupt = AddICRVector(CIAResource,CIAINTBIT,&CIATimerInterrupt)) != NULL)
X	{
X		fprintf(stderr,"cia timer interrupt already in use by '%s'",OldCIAInterrupt->is_Node.ln_Name);
X		EndCIATimer();
X		return(0);
X	}
X
X	SetCIATimer(CIA_TIME_SLICE);
X
X	StartCIATimer();
X	return(TRUE);
X}
X
Xmain()
X{
X	if (BeginCIATimer())
X	{
X		Wait(SIGBREAKF_CTRL_C);
X	}
X	else 
X		exit(1);
X
X	EndCIATimer();
X	exit(0);
X}
//END_OF_FILE
echo x - ciafinder.c
sed 's/^X//' > ciafinder.c << '//END_OF_FILE'
X/* TIMER - Amiga CIA Timer Control Software 0.1a
X
X  originally by Paul Higginbottom, Public Domain
X
X  hacked on by karl to produce a monotonically increasing microsecond
X  clock, 12/30/88, Public Domain
X
X  ciafinder is a companion program to ciatimer.  When ciatimer is running,
X  it has a timer interrupt installed for a CIA timer, ciafinder will locate
X  it and get the time.  ciafinder contains the code you need for your
X  application to find the microsecond-resolution CIA timer time.
X
X  cc +p ciafinder.c
X  ln ciafinder.o -lcl32
X
X*/
X
X#include <exec/types.h>
X#include <exec/tasks.h>
X#include <functions.h>
X#include <exec/interrupts.h>
X#include <hardware/cia.h>
X#include <hardware/custom.h>
X#include <hardware/intbits.h>
X#include <resources/cia.h>
X#include <stdio.h>
X
X#include "ciatimer.h"
X
X#define MATCH 0
X
Xstatic struct Interrupt
X   CIATimerInterrupt,
X   *OldCIAInterrupt = (struct Interrupt *)-1;
X
Xstatic struct Library *CIAResource = NULL;
X
X#define ciatlo ciaa.ciatalo
X#define ciathi ciaa.ciatahi
X#define ciacr ciaa.ciacra
X#define CIAINTBIT CIAICRB_TA
X#define CLEAR 0
X
Xvoid DummyCIAInterrupt()
X{
X}
X
Xstruct CIA_Time *LocateCIATimerData()
X{
X	/* Open the CIA resource */
X	if ((CIAResource = (struct Library *)OpenResource(CIAANAME)) == NULL)
X	{
X		fprintf(stderr,"timer couldn't open cia resource\n");
X		return(NULL);
X	}
X
X	CIATimerInterrupt.is_Node.ln_Type = NT_INTERRUPT;
X	CIATimerInterrupt.is_Node.ln_Pri = 127;
X	CIATimerInterrupt.is_Code = DummyCIAInterrupt;
X	CIATimerInterrupt.is_Node.ln_Name = "ciafinder dummy interrupt";
X
X	/* install interrupt */
X	if ((OldCIAInterrupt = AddICRVector(CIAResource,CIAINTBIT,&CIATimerInterrupt)) == NULL)
X	{
X		RemICRVector(CIAResource, CIAINTBIT, &CIATimerInterrupt);
X		fprintf(stderr,"no CIA timer currently installed!\n");
X		return(NULL);
X	}
X
X	if (strcmp(OldCIAInterrupt->is_Node.ln_Name,CIATIMER_INTERRUPT_NAME) != MATCH)
X	{
X		fprintf(stderr,"CIA interrupt routine is '%s' rather than '%s'\n",OldCIAInterrupt->is_Node.ln_Name,CIATIMER_INTERRUPT_NAME);
X		return(NULL);
X	}
X
X	return((struct CIA_Time *)OldCIAInterrupt->is_Data);
X}
X
X/* return the elapsed real time in seconds and microseconds since the
X * cia timer interrupt handler was installed.
X *
X * ElapsedTime(&secs,&microsecs);
X *
X */
Xvoid ElapsedTime(tickdata_ptr,sec_ptr,usec_ptr)
Xstruct CIA_Time *tickdata_ptr;
Xint *sec_ptr,*usec_ptr;
X{
X	register long seconds, microseconds;
X	register long ciahi, cialo;
X
X	Disable();
X	ciahi = ciathi;
X	cialo = ciatlo;
X	seconds = tickdata_ptr->CIA_Seconds;
X	microseconds = tickdata_ptr->CIA_Microseconds;
X	Enable();
X	/* total microseconds is CIA_BigTicks * 65536 + timerval * 1.397 */
X	/* to multiply the timer ticks * 1.397, you can multiply by 1430
X	 * and divide by 1024 (or shift right by 10, get it?) 
X	 */
X	ciahi = CIA_TIME_SLICE - ((ciahi << 8) + cialo);
X	ciahi = ((ciahi * 1430) >> 10) & 0xffff;
X
X	microseconds += ciahi;
X	if (microseconds > 1000000)
X	{
X		microseconds -= 1000000;
X		seconds++;
X	}
X
X	*sec_ptr = seconds;
X	*usec_ptr = microseconds;
X	return;
X}
X
Xmain()
X{
X	struct CIA_Time *CIA_CurrentTime_ptr;
X	long secs, microsecs;
X
X	CIA_CurrentTime_ptr = LocateCIATimerData();
X	if (CIA_CurrentTime_ptr == NULL)
X		exit(1);
X
X	ElapsedTime(CIA_CurrentTime_ptr,&secs,&microsecs);
X
X	printf("secs %d microsecs %d\n",secs,microsecs);
X}
//END_OF_FILE
echo "End of archive."
# end of archive.
exit 0
-- 
-- uunet!sugar!karl  | "We've been following your progress with considerable 
-- karl@sugar.uu.net |  interest, not to say contempt."  -- Zaphod Beeblebrox IV
-- Usenet BBS (713) 438-5018

higgin@cbmvax.UUCP (Paul Higginbottom MKT) (01/27/89)

In article <3252@sugar.uu.net> karl@sugar.uu.net (Karl Lehenbauer) writes:
$Below is a shar of my latest version of Paul Higginbottom's CIA timer
$routines. [deleted].

It's nice to see that something I did has been used, especially since it
has been taken from an example to a more general (and therefore useful)
solution.  Good job Karl.  I haven't tried yours yet, but I'm sure it works
as you advertise.

	Paul.