home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Amiga Elysian Archive
/
AmigaElysianArchive.iso
/
prog
/
c
/
rkrm1.lha
/
RKRM_Devices
/
RKRM_Devices.lha
/
Resources
/
CIA_interval.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-09-03
|
12KB
|
461 lines
/*
* Copyright (c) 1992 Commodore-Amiga, Inc.
*
* This example is provided in electronic form by Commodore-Amiga, Inc. for
* use with the "Amiga ROM Kernel Reference Manual: Devices", 3rd Edition,
* published by Addison-Wesley (ISBN 0-201-56775-X).
*
* The "Amiga ROM Kernel Reference Manual: Devices" contains additional
* information on the correct usage of the techniques and operating system
* functions presented in these examples. The source and executable code
* of these examples may only be distributed in free electronic form, via
* bulletin board or as part of a fully non-commercial and freely
* redistributable diskette. Both the source and executable code (including
* comments) must be included, without modification, in any copy. This
* example may not be published in printed form or distributed with any
* commercial product. However, the programming techniques and support
* routines set forth in these examples may be used in the development
* of original executable software products for Commodore Amiga computers.
*
* All other rights reserved.
*
* This example is provided "as-is" and is subject to change; no
* warranties are made. All use is at your own risk. No liability or
* responsibility is assumed.
*
*****************************************************************************
*
*
* Cia_Interval.c
*
* Demonstrate allocation and use of a cia interval timer
*
* Compile with SAS C 5.10 lc -b1 -cfistq -v -y -L
*
* Run from CLI only
*/
#include <exec/types.h>
#include <exec/memory.h>
#include <exec/tasks.h>
#include <exec/interrupts.h>
#include <hardware/cia.h>
#include <resources/cia.h>
#include <clib/exec_protos.h>
#include <clib/cia_protos.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
/* prototypes */
void StartTimer (struct freetimer *ft, struct exampledata *ed);
int FindFreeTimer (struct freetimer *ft, int preferA);
int TryTimer (struct freetimer *ft);
void main ( USHORT, char **);
/* see usage of these defines in StartTimer() below */
#define COUNTDOWN 20
#define HICOUNT 0xFF
#define LOCOUNT 0xFF
#define STOPA_AND CIACRAF_TODIN |CIACRAF_PBON | CIACRAF_OUTMODE | CIACRAF_SPMODE
/*
;
; AND mask for use with control register A
; (interval timer A on either CIA)
;
; STOP -
; START bit 0 == 0 (STOP IMMEDIATELY)
; PBON bit 1 == same
; OUT bit 2 == same
; RUN bit 3 == 0 (SET CONTINUOUS MODE)
; LOAD bit 4 == 0 (NO FORCE LOAD)
; IN bit 5 == 0 (COUNTS 02 PULSES)
; SP bit 6 == same
; TODIN bit 7 == same (unused on ciacra)
*/
#define STOPB_AND CIACRBF_ALARM | CIACRBF_PBON | CIACRBF_OUTMODE
/*
;
; AND mask for use with control register B
; (interval timer B on either CIA)
;
; STOP -
; START bit 0 == 0 (STOP IMMEDIATELY)
; PBON bit 1 == same
; OUT bit 2 == same
; RUN bit 3 == 0 (SET CONTINUOUS MODE)
; LOAD bit 4 == 0 (NO FORCE LOAD)
; IN0 bit 5 == 0 (COUNTS 02 PULSES)
; IN1 bit 6 == 0 (COUNTS 02 PULSES)
; ALARM bit 7 == same (TOD alarm control bit)
*/
#define STARTA_OR CIACRAF_START
/*
;
; OR mask for use with control register A
; (interval timer A on either CIA)
;
; START -
;
; START bit 0 == 1 (START TIMER)
;
; All other bits unaffected.
;
*/
#define STARTB_OR CIACRBF_START
/*
;
; OR mask for use with control register B
; (interval timer A on either CIA)
;
; START -
;
; START bit 0 == 1 (START TIMER)
;
; All other bits unaffected.
;
*/
/*
* Structure which will be used to hold all relevant information about
* the cia timer we manage to allocate.
*
*/
struct freetimer
{
struct Library *ciabase; /* CIA Library Base */
ULONG timerbit; /* timer bit allocated */
struct CIA *cia; /* ptr to hardware */
UBYTE *ciacr; /* ptr to control register */
UBYTE *cialo; /* ptr to low byte of timer */
UBYTE *ciahi; /* ptr to high byte of timer */
struct Interrupt timerint; /* Interrupt structure */
UBYTE stopmask; /* Stop/set-up timer */
UBYTE startmask; /* Start timer */
};
/*
* Structure which will be used by the interrupt routine called
* when our cia interval timer generates an interrupt.
*
*/
struct exampledata
{
struct Task *task; /* task to signal */
ULONG signal; /* Signal bit to use */
ULONG counter;
};
struct CIA *ciaa = (struct CIA *)0xbfe001;
struct CIA *ciab = (struct CIA *)0xbfd000;
#ifdef LATTICE
int CXBRK(void) { return(0); } /* Disable SAS CTRL/C handling */
int chkabort(void) { return(0); } /* really */
#endif
/*
* This is the interrupt routine which will be called when our CIA
* interval timer counts down.
*
* This example decrements a counter each time the interrupt routine
* is called until the counter reaches 0, at which time it signals
* our main task.
*
* Note that interrupt handling code should be efficient, and will
* generally be written in assembly code. Signaling another task
* such as this example does is also a useful way of handling
* interrupts in an expedient manner.
*
*/
void __asm ExampleInterrupt(register __a1 struct exampledata *ed)
{
if (ed->counter)
{
ed->counter--; /* decrement counter */
}
else
{
ed->counter = COUNTDOWN; /* reset counter */
Signal(ed->task,(1L << ed->signal));
}
}
/***********************************
* main()
***********************************/
void main(USHORT argc,char **argv)
{
struct freetimer ft;
struct exampledata ed;
/* Set up data which will be passed to interrupt */
ed.task = FindTask(0L);
if (ed.signal = AllocSignal(-1L))
{
/* Prepare freetimer structure : set-up interrupt */
ft.timerint.is_Node.ln_Type = NT_INTERRUPT;
ft.timerint.is_Node.ln_Pri = 0;
ft.timerint.is_Node.ln_Name = "cia_example";
ft.timerint.is_Data = (APTR)&ed;
ft.timerint.is_Code = (APTR)ExampleInterrupt;
/* Call function to find a free CIA interval timer
* with flag indicating that we prefer a CIA-A timer.
*/
printf("Attempting to allocate a free timer\n");
if (FindFreeTimer(&ft,TRUE))
{
if (ft.cia == ciaa)
{
printf("CIA-A timer ");
}
else
{
printf("CIA-B timer ");
}
if (ft.timerbit == CIAICRB_TA)
{
printf("A allocated\n");
}
else
{
printf("B allocated\n");
}
/* We found a free interval timer. Let's start it running. */
StartTimer(&ft,&ed);
/* Wait for a signal */
printf("Waiting for signal bit %ld\n",ed.signal);
Wait(1L<<ed.signal);
printf("We woke up!\n");
/* Release the interval timer */
RemICRVector(ft.ciabase,ft.timerbit,&ft.timerint);
}
else
{
printf("No CIA interval timer available\n");
}
FreeSignal(ed.signal);
}
}
/*
* This routine sets up the interval timer we allocated with
* AddICRVector(). Note that we may have already received one, or
* more interrupts from our timer. Make no assumptions about the
* initial state of any of the hardware registers we will be using.
*
*/
void StartTimer(struct freetimer *ft, struct exampledata *ed)
{
register struct CIA *cia;
cia = ft->cia;
/* Note that there are differences between control register A,
* and B on each CIA (e.g., the TOD alarm bit, and INMODE bits.
*/
if (ft->timerbit == CIAICRB_TA)
{
ft->ciacr = &cia->ciacra; /* control register A */
ft->cialo = &cia->ciatalo; /* low byte counter */
ft->ciahi = &cia->ciatahi; /* high byte counter */
ft->stopmask = STOPA_AND; /* set-up mask values */
ft->startmask = STARTA_OR;
}
else
{
ft->ciacr = &cia->ciacrb; /* control register B */
ft->cialo = &cia->ciatblo; /* low byte counter */
ft->ciahi = &cia->ciatbhi; /* high byte counter */
ft->stopmask = STOPB_AND; /* set-up mask values */
ft->startmask = STARTB_OR;
}
/* Modify control register within Disable(). This is done to avoid
* race conditions since our compiler may generate code such as:
*
* value = Read hardware byte
* AND value with MASK
* Write value to hardware byte
*
* If we take a task switch in the middle of this sequence, two tasks
* trying to modify the same register could trash each others' bits.
*
* Normally this code would be written in assembly language using atomic
* instructions so that the Disable() would not be needed.
*/
Disable();
/* STOP timer, set 02 pulse count-down mode, set continuous mode */
*ft->ciacr &= ft->stopmask;
Enable();
/* Clear signal bit - interrupt will signal us later */
SetSignal(0L,1L<<ed->signal);
/* Count-down X # of times */
ed->counter = COUNTDOWN;
/* Start the interval timer - we will start the counter after
* writing the low, and high byte counter values
*/
*ft->cialo = LOCOUNT;
*ft->ciahi = HICOUNT;
/* Turn on start bit - same bit for both A, and B control regs */
Disable();
*ft->ciacr |= ft->startmask;
Enable();
}
/*
* A routine to find a free interval timer.
*
* This routine makes no assumptions about which interval timers
* (if any) are available for use. Currently there are two interval
* timers per CIA chip.
*
* Because CIA usage may change in the future, your code should use
* a routine like this to find a free interval timer.
*
* Note that the routine takes a preference flag (which is used to
* to indicate that you would prefer an interval timer on CIA-A).
* If the flag is FALSE, it means that you would prefer an interval
* timer on CIA-B.
*
*/
FindFreeTimer(struct freetimer *ft, int preferA)
{
struct CIABase *ciaabase, *ciabbase;
/* get pointers to both resource bases */
ciaabase = OpenResource(CIAANAME);
ciabbase = OpenResource(CIABNAME);
/* try for a CIA-A timer first ? */
if (preferA)
{
ft->ciabase = ciaabase; /* library address */
ft->cia = ciaa; /* hardware address */
}
else
{
ft->ciabase = ciabbase; /* library address */
ft->cia = ciab; /* hardware address */
}
if (TryTimer(ft))
return(TRUE);
/* try for an interval timer on the other cia */
if (!(preferA))
{
ft->ciabase = ciaabase; /* library address */
ft->cia = ciaa; /* hardware address */
}
else
{
ft->ciabase = ciabbase; /* library address */
ft->cia = ciab; /* hardware address */
}
if (TryTimer(ft))
return(TRUE);
return(FALSE);
}
/*
* Try to obtain a free interval timer on a CIA.
*/
TryTimer(struct freetimer *ft)
{
if (!(AddICRVector(ft->ciabase,CIAICRB_TA,&ft->timerint)))
{
ft->timerbit = CIAICRB_TA;
return(TRUE);
}
if (!(AddICRVector(ft->ciabase,CIAICRB_TB,&ft->timerint)))
{
ft->timerbit = CIAICRB_TB;
return(TRUE);
}
return(FALSE);
}