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 >
C/C++ Source or Header  |  1992-09-03  |  12KB  |  461 lines

  1. /*
  2.  * Copyright (c) 1992 Commodore-Amiga, Inc.
  3.  * 
  4.  * This example is provided in electronic form by Commodore-Amiga, Inc. for 
  5.  * use with the "Amiga ROM Kernel Reference Manual: Devices", 3rd Edition, 
  6.  * published by Addison-Wesley (ISBN 0-201-56775-X).
  7.  * 
  8.  * The "Amiga ROM Kernel Reference Manual: Devices" contains additional 
  9.  * information on the correct usage of the techniques and operating system 
  10.  * functions presented in these examples.  The source and executable code 
  11.  * of these examples may only be distributed in free electronic form, via 
  12.  * bulletin board or as part of a fully non-commercial and freely 
  13.  * redistributable diskette.  Both the source and executable code (including 
  14.  * comments) must be included, without modification, in any copy.  This 
  15.  * example may not be published in printed form or distributed with any
  16.  * commercial product.  However, the programming techniques and support
  17.  * routines set forth in these examples may be used in the development
  18.  * of original executable software products for Commodore Amiga computers.
  19.  * 
  20.  * All other rights reserved.
  21.  * 
  22.  * This example is provided "as-is" and is subject to change; no
  23.  * warranties are made.  All use is at your own risk. No liability or
  24.  * responsibility is assumed.
  25.  *
  26.  *****************************************************************************
  27.  *
  28.  *
  29.  * Cia_Interval.c
  30.  *
  31.  * Demonstrate allocation and use of a cia interval timer
  32.  *
  33.  * Compile with SAS C 5.10  lc -b1 -cfistq -v -y -L
  34.  *
  35.  * Run from CLI only
  36.  */
  37.  
  38. #include <exec/types.h>
  39. #include <exec/memory.h>
  40. #include <exec/tasks.h>
  41. #include <exec/interrupts.h>
  42. #include <hardware/cia.h>
  43. #include <resources/cia.h>
  44.  
  45. #include <clib/exec_protos.h>
  46. #include <clib/cia_protos.h>
  47.  
  48. #include <stdlib.h>
  49. #include <stdio.h>
  50. #include <string.h>
  51.  
  52.  
  53. /* prototypes */
  54.  
  55. void    StartTimer      (struct freetimer *ft, struct exampledata *ed);
  56. int     FindFreeTimer   (struct freetimer *ft, int preferA);
  57. int     TryTimer        (struct freetimer *ft);
  58. void    main            ( USHORT, char **);
  59.  
  60.  
  61. /* see usage of these defines in StartTimer() below */
  62.  
  63. #define COUNTDOWN 20
  64. #define HICOUNT 0xFF
  65. #define LOCOUNT 0xFF
  66.  
  67. #define STOPA_AND  CIACRAF_TODIN |CIACRAF_PBON | CIACRAF_OUTMODE | CIACRAF_SPMODE
  68.  
  69.         /*
  70.         ;
  71.         ; AND mask for use with control register A
  72.         ; (interval timer A on either CIA)
  73.         ;
  74.         ; STOP -
  75.         ;       START bit 0 == 0 (STOP IMMEDIATELY)
  76.         ;       PBON  bit 1 == same
  77.         ;       OUT   bit 2 == same
  78.         ;       RUN   bit 3 == 0 (SET CONTINUOUS MODE)
  79.         ;       LOAD  bit 4 == 0 (NO FORCE LOAD)
  80.         ;       IN    bit 5 == 0 (COUNTS 02 PULSES)
  81.         ;       SP    bit 6 == same
  82.         ;       TODIN bit 7 == same (unused on ciacra)
  83.  
  84.         */
  85.  
  86. #define STOPB_AND  CIACRBF_ALARM | CIACRBF_PBON | CIACRBF_OUTMODE
  87.  
  88.         /*
  89.         ;
  90.         ; AND mask for use with control register B
  91.         ; (interval timer B on either CIA)
  92.         ;
  93.         ; STOP -
  94.         ;       START bit 0 == 0 (STOP IMMEDIATELY)
  95.         ;       PBON  bit 1 == same
  96.         ;       OUT   bit 2 == same
  97.         ;       RUN   bit 3 == 0 (SET CONTINUOUS MODE)
  98.         ;       LOAD  bit 4 == 0 (NO FORCE LOAD)
  99.         ;       IN0   bit 5 == 0 (COUNTS 02 PULSES)
  100.         ;       IN1   bit 6 == 0 (COUNTS 02 PULSES)
  101.         ;       ALARM bit 7 == same (TOD alarm control bit)
  102.  
  103.         */
  104.  
  105. #define STARTA_OR  CIACRAF_START
  106.  
  107.         /*
  108.         ;
  109.         ; OR mask for use with control register A
  110.         ; (interval timer A on either CIA)
  111.         ;
  112.         ; START -
  113.         ;
  114.         ;       START bit 0 == 1 (START TIMER)
  115.         ;
  116.         ;       All other bits unaffected.
  117.         ;
  118.  
  119.         */
  120.  
  121. #define STARTB_OR  CIACRBF_START
  122.  
  123.         /*
  124.         ;
  125.         ; OR mask for use with control register B
  126.         ; (interval timer A on either CIA)
  127.         ;
  128.         ; START -
  129.         ;
  130.         ;       START bit 0 == 1 (START TIMER)
  131.         ;
  132.         ;       All other bits unaffected.
  133.         ;
  134.  
  135.         */
  136.  
  137.  
  138. /*
  139.  * Structure which will be used to hold all relevant information about
  140.  * the cia timer we manage to allocate.
  141.  *
  142.  */
  143.  
  144. struct freetimer
  145. {
  146.     struct Library *ciabase;        /* CIA Library Base             */
  147.     ULONG  timerbit;                /* timer bit allocated          */
  148.     struct CIA *cia;                /* ptr to hardware              */
  149.     UBYTE *ciacr;                   /* ptr to control register      */
  150.     UBYTE *cialo;                   /* ptr to low byte of timer     */
  151.     UBYTE *ciahi;                   /* ptr to high byte of timer    */
  152.     struct Interrupt timerint;      /* Interrupt structure          */
  153.     UBYTE  stopmask;                /* Stop/set-up timer            */
  154.     UBYTE  startmask;               /* Start timer                  */
  155. };
  156.  
  157. /*
  158.  * Structure which will be used by the interrupt routine called
  159.  * when our cia interval timer generates an interrupt.
  160.  *
  161.  */
  162.  
  163. struct exampledata
  164. {
  165.     struct Task *task;      /* task to signal */
  166.     ULONG   signal;         /* Signal bit to use */
  167.     ULONG   counter;
  168. };
  169.  
  170.  
  171. struct CIA *ciaa = (struct CIA *)0xbfe001;
  172. struct CIA *ciab = (struct CIA *)0xbfd000;
  173.  
  174.  
  175. #ifdef LATTICE
  176. int CXBRK(void) { return(0); }  /* Disable SAS CTRL/C handling */
  177. int chkabort(void) { return(0); }  /* really */
  178. #endif
  179.  
  180. /*
  181.  * This is the interrupt routine which will be called when our CIA
  182.  * interval timer counts down.
  183.  *
  184.  * This example decrements a counter each time the interrupt routine
  185.  * is called until the counter reaches 0, at which time it signals
  186.  * our main task.
  187.  *
  188.  * Note that interrupt handling code should be efficient, and will
  189.  * generally be written in assembly code.  Signaling another task
  190.  * such as this example does is also a useful way of handling
  191.  * interrupts in an expedient manner.
  192.  *
  193.  */
  194.  
  195. void __asm ExampleInterrupt(register __a1 struct exampledata *ed)
  196. {
  197.  
  198. if (ed->counter)
  199.     {
  200.     ed->counter--;                  /* decrement counter */
  201.     }
  202. else
  203.     {
  204.     ed->counter = COUNTDOWN;        /* reset counter     */
  205.  
  206.     Signal(ed->task,(1L << ed->signal));
  207.     }
  208. }
  209.  
  210. /***********************************
  211.  *  main()
  212.  ***********************************/
  213. void main(USHORT argc,char **argv)
  214. {
  215.  
  216. struct freetimer ft;
  217. struct exampledata ed;
  218.  
  219.  
  220. /* Set up data which will be passed to interrupt */
  221.  
  222. ed.task = FindTask(0L);
  223.  
  224. if (ed.signal = AllocSignal(-1L))
  225.     {
  226.  
  227.     /* Prepare freetimer structure : set-up interrupt */
  228.  
  229.     ft.timerint.is_Node.ln_Type = NT_INTERRUPT;
  230.     ft.timerint.is_Node.ln_Pri  = 0;
  231.     ft.timerint.is_Node.ln_Name = "cia_example";
  232.  
  233.     ft.timerint.is_Data         = (APTR)&ed;
  234.     ft.timerint.is_Code         = (APTR)ExampleInterrupt;
  235.  
  236.  
  237.     /* Call function to find a free CIA interval timer
  238.      * with flag indicating that we prefer a CIA-A timer.
  239.      */
  240.  
  241.     printf("Attempting to allocate a free timer\n");
  242.  
  243.     if (FindFreeTimer(&ft,TRUE))
  244.         {
  245.  
  246.         if (ft.cia == ciaa)
  247.             {
  248.             printf("CIA-A timer ");
  249.             }
  250.         else
  251.             {
  252.             printf("CIA-B timer ");
  253.             }
  254.  
  255.         if (ft.timerbit == CIAICRB_TA)
  256.             {
  257.             printf("A allocated\n");
  258.             }
  259.         else
  260.             {
  261.             printf("B allocated\n");
  262.             }
  263.  
  264.  
  265.         /* We found a free interval timer.  Let's start it running. */
  266.  
  267.         StartTimer(&ft,&ed);
  268.  
  269.         /* Wait for a signal */
  270.  
  271.         printf("Waiting for signal bit %ld\n",ed.signal);
  272.  
  273.         Wait(1L<<ed.signal);
  274.  
  275.         printf("We woke up!\n");
  276.  
  277.         /* Release the interval timer */
  278.  
  279.         RemICRVector(ft.ciabase,ft.timerbit,&ft.timerint);
  280.  
  281.         }
  282.     else
  283.         {
  284.         printf("No CIA interval timer available\n");
  285.         }
  286.  
  287.     FreeSignal(ed.signal);
  288.     }
  289. }
  290.  
  291.  
  292. /*
  293.  * This routine sets up the interval timer we allocated with
  294.  * AddICRVector().  Note that we may have already received one, or
  295.  * more interrupts from our timer.  Make no assumptions about the
  296.  * initial state of any of the hardware registers we will be using.
  297.  *
  298.  */
  299.  
  300. void StartTimer(struct freetimer *ft, struct exampledata *ed)
  301. {
  302. register struct CIA *cia;
  303.  
  304. cia = ft->cia;
  305.  
  306. /* Note that there are differences between control register A,
  307.  * and B on each CIA (e.g., the TOD alarm bit, and INMODE bits.
  308.  */
  309.  
  310. if (ft->timerbit == CIAICRB_TA)
  311.     {
  312.     ft->ciacr = &cia->ciacra;       /* control register A   */
  313.     ft->cialo = &cia->ciatalo;      /* low byte counter     */
  314.     ft->ciahi = &cia->ciatahi;      /* high byte counter    */
  315.  
  316.     ft->stopmask = STOPA_AND;       /* set-up mask values   */
  317.     ft->startmask = STARTA_OR;
  318.     }
  319. else
  320.     {
  321.     ft->ciacr = &cia->ciacrb;       /* control register B   */
  322.     ft->cialo = &cia->ciatblo;      /* low byte counter     */
  323.     ft->ciahi = &cia->ciatbhi;      /* high byte counter    */
  324.  
  325.     ft->stopmask = STOPB_AND;       /* set-up mask values   */
  326.     ft->startmask = STARTB_OR;
  327.     }
  328.  
  329.  
  330. /* Modify control register within Disable().  This is done to avoid
  331.  * race conditions since our compiler may generate code such as:
  332.  *
  333.  *      value = Read hardware byte
  334.  *      AND  value with MASK
  335.  *      Write value to hardware byte
  336.  *
  337.  * If we take a task switch in the middle of this sequence, two tasks
  338.  * trying to modify the same register could trash each others' bits.
  339.  *
  340.  * Normally this code would be written in assembly language using atomic
  341.  * instructions so that the Disable() would not be needed.
  342.  */
  343.  
  344.  
  345. Disable();
  346.  
  347. /* STOP timer, set 02 pulse count-down mode, set continuous mode */
  348.  
  349. *ft->ciacr &= ft->stopmask;
  350. Enable();
  351.  
  352. /* Clear signal bit - interrupt will signal us later */
  353. SetSignal(0L,1L<<ed->signal);
  354.  
  355. /* Count-down X # of times */
  356. ed->counter = COUNTDOWN;
  357.  
  358. /* Start the interval timer - we will start the counter after
  359.  * writing the low, and high byte counter values
  360.  */
  361.  
  362. *ft->cialo = LOCOUNT;
  363. *ft->ciahi = HICOUNT;
  364.  
  365. /* Turn on start bit - same bit for both A, and B control regs  */
  366.  
  367. Disable();
  368. *ft->ciacr |= ft->startmask;
  369.  
  370. Enable();
  371. }
  372.  
  373.  
  374.  
  375. /*
  376.  * A routine to find a free interval timer.
  377.  *
  378.  * This routine makes no assumptions about which interval timers
  379.  * (if any) are available for use.  Currently there are two interval
  380.  * timers per CIA chip.
  381.  *
  382.  * Because CIA usage may change in the future, your code should use
  383.  * a routine like this to find a free interval timer.
  384.  *
  385.  * Note that the routine takes a preference flag (which is used to
  386.  * to indicate that you would prefer an interval timer on CIA-A).
  387.  * If the flag is FALSE, it means that you would prefer an interval
  388.  * timer on CIA-B.
  389.  *
  390.  */
  391.  
  392. FindFreeTimer(struct freetimer *ft, int preferA)
  393. {
  394. struct CIABase *ciaabase, *ciabbase;
  395.  
  396. /* get pointers to both resource bases */
  397.  
  398. ciaabase = OpenResource(CIAANAME);
  399. ciabbase = OpenResource(CIABNAME);
  400.  
  401. /* try for a CIA-A timer first ? */
  402.  
  403. if (preferA)
  404.     {
  405.     ft->ciabase = ciaabase; /* library address  */
  406.     ft->cia     = ciaa;     /* hardware address */
  407.     }
  408. else
  409.     {
  410.     ft->ciabase = ciabbase; /* library address  */
  411.     ft->cia     = ciab;     /* hardware address */
  412.     }
  413.  
  414. if (TryTimer(ft))
  415.     return(TRUE);
  416.  
  417. /* try for an interval timer on the other cia */
  418.  
  419. if (!(preferA))
  420.     {
  421.     ft->ciabase = ciaabase; /* library address  */
  422.     ft->cia     = ciaa;     /* hardware address */
  423.     }
  424. else
  425.     {
  426.     ft->ciabase = ciabbase; /* library address  */
  427.     ft->cia     = ciab;     /* hardware address */
  428.     }
  429.  
  430. if (TryTimer(ft))
  431.     return(TRUE);
  432.  
  433. return(FALSE);
  434.  
  435. }
  436.  
  437.  
  438. /*
  439.  * Try to obtain a free interval timer on a CIA.
  440.  */
  441.  
  442. TryTimer(struct freetimer *ft)
  443. {
  444.  
  445. if (!(AddICRVector(ft->ciabase,CIAICRB_TA,&ft->timerint)))
  446.     {
  447.     ft->timerbit = CIAICRB_TA;
  448.     return(TRUE);
  449.     }
  450.  
  451. if (!(AddICRVector(ft->ciabase,CIAICRB_TB,&ft->timerint)))
  452.     {
  453.     ft->timerbit = CIAICRB_TB;
  454.     return(TRUE);
  455.     }
  456.  
  457. return(FALSE);
  458. }
  459.  
  460.  
  461.