home *** CD-ROM | disk | FTP | other *** search
/ Amiga MA Magazine 1998 #6 / amigamamagazinepolishissue1998.iso / coders / jËzyki_programowania / amigae / e_v3.2a / rkrmsrc / resources / cia_interval.e < prev    next >
Text File  |  1977-12-31  |  9KB  |  272 lines

  1. -> Cia_Interval.e - Demonstrate allocation and use of a cia interval timer
  2.  
  3. OPT PREPROCESS
  4.  
  5. -> E-Note: we need eCodeIntServer() in order to use an E PROC as a CIA interrupt
  6. MODULE 'other/cia',
  7.        'other/ecode',
  8.        'exec/interrupts',
  9.        'exec/libraries',
  10.        'exec/nodes',
  11.        'exec/tasks',
  12.        'hardware/cia',
  13.        'resources/cia'
  14.  
  15. ENUM ERR_NONE, ERR_ECODE, ERR_SIG, ERR_TIMER
  16.  
  17. CONST COUNTDOWN=20, HICOUNT=$FF, LOCOUNT=$FF
  18.  
  19. CONST STOPA_AND=CIACRAF_TODIN OR CIACRAF_PBON OR
  20.                 CIACRAF_OUTMODE OR CIACRAF_SPMODE
  21.    ->
  22.    -> AND mask for use with control register A
  23.    -> (interval timer A on either CIA)
  24.    ->
  25.    -> STOP -
  26.    ->       START bit 0 == 0 (STOP IMMEDIATELY)
  27.    ->       PBON  bit 1 == same
  28.    ->       OUT   bit 2 == same
  29.    ->       RUN   bit 3 == 0 (SET CONTINUOUS MODE)
  30.    ->       LOAD  bit 4 == 0 (NO FORCE LOAD)
  31.    ->       IN    bit 5 == 0 (COUNTS 02 PULSES)
  32.    ->       SP    bit 6 == same
  33.    ->       TODIN bit 7 == same (unused on ciacra)
  34.  
  35. CONST STOPB_AND=CIACRBF_ALARM OR CIACRBF_PBON OR CIACRBF_OUTMODE
  36.    ->
  37.    -> AND mask for use with control register B
  38.    -> (interval timer B on either CIA)
  39.    ->
  40.    -> STOP -
  41.    ->       START bit 0 == 0 (STOP IMMEDIATELY)
  42.    ->       PBON  bit 1 == same
  43.    ->       OUT   bit 2 == same
  44.    ->       RUN   bit 3 == 0 (SET CONTINUOUS MODE)
  45.    ->       LOAD  bit 4 == 0 (NO FORCE LOAD)
  46.    ->       IN0   bit 5 == 0 (COUNTS 02 PULSES)
  47.    ->       IN1   bit 6 == 0 (COUNTS 02 PULSES)
  48.    ->       ALARM bit 7 == same (TOD alarm control bit)
  49.  
  50. CONST STARTA_OR=CIACRAF_START
  51.    ->
  52.    -> OR mask for use with control register A
  53.    -> (interval timer A on either CIA)
  54.    ->
  55.    -> START -
  56.    ->
  57.    ->       START bit 0 == 1 (START TIMER)
  58.    ->
  59.    ->       All other bits unaffected.
  60.  
  61. CONST STARTB_OR=CIACRBF_START
  62.    ->
  63.    -> OR mask for use with control register B
  64.    -> (interval timer A on either CIA)
  65.    ->
  66.    -> START -
  67.    ->
  68.    ->       START bit 0 == 1 (START TIMER)
  69.    ->
  70.    ->       All other bits unaffected.
  71.  
  72. -> Structure which will be used to hold all relevant information about cia
  73. -> timer we manage to allocate.
  74. OBJECT freetimer
  75.   ciabase            -> CIA Library Base
  76.   timerbit           -> Timer bit allocated
  77.   cia                -> Pointer to hardware
  78.   ciacr:PTR TO CHAR  -> Pointer to control register
  79.   cialo:PTR TO CHAR  -> Pointer to low byte of timer
  80.   ciahi:PTR TO CHAR  -> Pointer to high byte of timer
  81.   timerint:is        -> Interrupt structure
  82.   stopmask:CHAR      -> Stop/set-up timer
  83.   startmask:CHAR     -> Start timer
  84. ENDOBJECT
  85.  
  86. -> Structure which will be used by the interrupt routine called when our
  87. -> cia interval timer generates an interrupt.
  88. OBJECT exampledata
  89.   task    -> Task to signal
  90.   signal  -> Signal bit to use
  91.   counter
  92. ENDOBJECT
  93.  
  94. DEF ciaa=CIAA_ADDR:PTR TO cia, ciab=CIAB_ADDR:PTR TO cia
  95.  
  96. -> This is the interrupt routine which will be called when our CIA interval
  97. -> timer counts down.
  98. ->
  99. -> This example decrements a counter each time the interrupt routine is called
  100. -> until the counter reaches 0, at which time it signals our main task.
  101. ->
  102. -> Note that interrupt handling code should be efficient, and will generally be
  103. -> written in assembly code.  Signaling another task such as this example does
  104. -> is also a useful way of handling interrupts in an expedient manner.
  105. -> E-Note: thanks to eCodeIntServer() we get ft.timerint.data as an argument
  106. PROC exampleInterrupt(ed:PTR TO exampledata)
  107.   IF ed.counter
  108.     ed.counter:=ed.counter-1  -> Decrement counter
  109.   ELSE
  110.     ed.counter:=COUNTDOWN     -> Reset counter
  111.     Signal(ed.task, Shl(1, ed.signal))
  112.   ENDIF
  113. ENDPROC
  114.  
  115. PROC main() HANDLE
  116.   DEF ft:freetimer, ed:exampledata
  117.  
  118.   -> Set up data which will be passed to interrupt
  119.   ed.task:=FindTask(NIL)
  120.  
  121.   -> E-Note: C version doesn't check the return value properly
  122.   ed.signal:=AllocSignal(-1)
  123.   IF ed.signal=-1 THEN Raise(ERR_SIG)
  124.  
  125.   -> Prepare freetimer object: set-up interrupt
  126.   ft.timerint.ln.type:=NT_INTERRUPT
  127.   ft.timerint.ln.pri:=0
  128.   ft.timerint.ln.name:='cia_example'
  129.  
  130.   ft.timerint.data:=ed
  131.   -> E-Note: eCodeIntServer() wraps an E PROC for use as a CIA interrupt
  132.   ft.timerint.code:=eCodeIntServer({exampleInterrupt})
  133.   IF ft.timerint.code=NIL THEN Raise(ERR_ECODE)
  134.  
  135.   -> Call function to find a free CIA interval timer with flag indicating
  136.   -> that we prefer a CIA-A timer.
  137.   WriteF('Attempting to allocate a free timer\n')
  138.  
  139.   findFreeTimer(ft, TRUE)
  140.  
  141.   WriteF('CIA-\c timer ', IF ft.cia=ciaa THEN "A" ELSE "B")
  142.  
  143.   WriteF('\c allocated\n', IF ft.timerbit=CIAICRB_TA THEN "A" ELSE "B")
  144.  
  145.   -> We found a free interval timer.  Let's start it running.
  146.   startTimer(ft, ed)
  147.  
  148.   -> Wait for a signal
  149.   WriteF('Waiting for signal bit \d\n', ed.signal)
  150.  
  151.   Wait(Shl(1, ed.signal))
  152.  
  153.   WriteF('We woke up!\n')
  154.  
  155.   -> Release the interval timer
  156.   remICRVector(ft.ciabase, ft.timerbit, ft.timerint)
  157.  
  158. EXCEPT DO
  159.   IF ed.signal<>-1 THEN FreeSignal(ed.signal)
  160.   SELECT exception
  161.   CASE ERR_ECODE;  WriteF('Ran out of memory in eCodeIntServer()\n')
  162.   CASE ERR_SIG;    WriteF('Could not allocate signal\n')
  163.   CASE ERR_TIMER;  WriteF('No CIA interval timer available\n')
  164.   ENDSELECT
  165. ENDPROC
  166.  
  167. -> This routine sets up the interval timer we allocated with addICRVector().
  168. -> Note that we may have already received one, or more interrupts from our
  169. -> timer.  Make no assumptions about the initial state of any of the hardware
  170. -> registers we will be using.
  171. PROC startTimer(ft:PTR TO freetimer, ed:PTR TO exampledata)
  172.   DEF cia:PTR TO cia
  173.   cia:=ft.cia
  174.  
  175.   -> Note that there are differences between control register A, and B on
  176.   -> each CIA (e.g., the TOD alarm bit, and INMODE bits).
  177.   IF ft.timerbit=CIAICRB_TA
  178.     -> E-Note: use offsets to get addresses of the CIA bytes
  179.     ft.ciacr:=cia+CIACRA    -> Control register A
  180.     ft.cialo:=cia+CIATALO   -> Low byte counter
  181.     ft.ciahi:=cia+CIATAHI   -> High byte counter
  182.  
  183.     ft.stopmask:=STOPA_AND  -> Set-up mask values
  184.     ft.startmask:=STARTA_OR
  185.   ELSE
  186.     ft.ciacr:=cia+CIACRB    -> Control register B
  187.     ft.cialo:=cia+CIATBLO   -> Low byte counter
  188.     ft.ciahi:=cia+CIATBHI   -> High byte counter
  189.  
  190.     ft.stopmask:=STOPB_AND  -> Set-up mask values
  191.     ft.startmask:=STARTB_OR
  192.   ENDIF
  193.  
  194.   -> Modify control register within Disable().  This is done to avoid race
  195.   -> conditions since code like this will be generated:
  196.   ->
  197.   ->      value = Read hardware byte
  198.   ->      AND  value with MASK
  199.   ->      Write value to hardware byte
  200.   ->
  201.   -> If we take a task switch in the middle of this sequence, two tasks trying
  202.   -> to modify the same register could trash each others' bits.
  203.   ->
  204.   -> Normally this code would be written in Assembly language using atomic
  205.   -> instructions so that the Disable() would not be needed.
  206.  
  207.   Disable()
  208.   -> STOP timer, set 02 pulse count-down mode, set continuous mode
  209.   ft.ciacr[]:=ft.ciacr[] AND ft.stopmask
  210.   Enable()
  211.  
  212.   -> Clear signal bit - interrupt will signal us later
  213.   SetSignal(NIL, Shl(1, ed.signal))
  214.  
  215.   -> Count-down X number of times
  216.   ed.counter:=COUNTDOWN
  217.  
  218.   -> Start the interval timer - we will start the counter after writing the
  219.   -> low, and high byte counter values.
  220.   ft.cialo[]:=LOCOUNT
  221.   ft.ciahi[]:=HICOUNT
  222.  
  223.   -> Turn on start bit - same bit for both A, and B control regs
  224.   Disable()
  225.   ft.ciacr[]:=ft.ciacr[] OR ft.startmask
  226.   Enable()
  227. ENDPROC
  228.  
  229. -> A routine to find a free interval timer.
  230. ->
  231. -> This routine makes no assumptions about which interval timers (if any) are
  232. -> available for use.  Currently there are two interval timers per CIA chip.
  233. ->
  234. -> Because CIA usage may change in the future, your code should use a routine
  235. -> like this to find a free interval timer.
  236. ->
  237. -> Note that the routine takes a preference flag (which is used to indicate
  238. -> that you would prefer an interval timer on CIA-A).  If the flag is FALSE,
  239. -> it means that you would prefer an interval timer on CIA-B.
  240. PROC findFreeTimer(ft:PTR TO freetimer, preferA)
  241.   DEF ciaabase, ciabbase
  242.  
  243.   -> Get pointers to both Resource bases
  244.   ciaabase:=OpenResource(CIAANAME)
  245.   ciabbase:=OpenResource(CIABNAME)
  246.  
  247.   -> Try for a CIA-A timer first?
  248.   ft.ciabase:=IF preferA THEN ciaabase ELSE ciabbase  -> Library address
  249.   ft.cia:=IF preferA THEN ciaa ELSE ciab              -> Hardware address
  250.  
  251.   IF tryTimer(ft) THEN RETURN
  252.  
  253.   -> Try for an interval timer on the other cia
  254.   ft.ciabase:=IF preferA THEN ciabbase ELSE ciaabase  -> Library address
  255.   ft.cia:=IF preferA THEN ciab ELSE ciaa              -> Hardware address
  256.  
  257.   IF tryTimer(ft)=FALSE THEN Raise(ERR_TIMER)
  258. ENDPROC
  259.  
  260. -> Try to obtain a free interval timer on a CIA.
  261. PROC tryTimer(ft:PTR TO freetimer)
  262.   IF NIL=addICRVector(ft.ciabase, CIAICRB_TA, ft.timerint)
  263.     ft.timerbit:=CIAICRB_TA
  264.     RETURN TRUE
  265.   ENDIF
  266.  
  267.   IF NIL=addICRVector(ft.ciabase, CIAICRB_TB, ft.timerint)
  268.     ft.timerbit:=CIAICRB_TB
  269.     RETURN TRUE
  270.   ENDIF
  271. ENDPROC FALSE
  272.