[comp.sys.amiga.tech] CIA Timer Example

cs161agc@sdcc10.ucsd.EDU (John Schultz) (12/29/88)

  Ok, here's what I've got so far:


IMPLEMENTATION MODULE CIATimer;

FROM SYSTEM IMPORT ADDRESS,ADR,BYTE,INLINE;
FROM InOut IMPORT WriteString;
FROM CIAHardware IMPORT ciaa,CIABITS,CIAicrTB;
FROM CIAResource IMPORT AbleICR,AddICRVector,RemICRVector,SetICR,
                        CIAAName;
FROM Resources IMPORT OpenResource,ResourcePtr;
FROM Interrupts IMPORT Interrupt,InterruptPtr;
FROM Nodes IMPORT NTInterrupt;

CONST
  TIMERON    = CIABITS(1);
  TIMEROFF   = CIABITS(0);

  LATCHLOW   = CIABITS(0CCH); (* 2CCH = 716, for 1000hz *)
  LATCHHIGH  = CIABITS(002H);

VAR
  CIAResource : ResourcePtr;
  timer       : Interrupt;
  oldint      : InterruptPtr;

  oldciacrb,  (* So we can restore them later *) 
  oldciatblo,
  oldciatbhi  : CIABITS;

PROCEDURE ResetTimer;
BEGIN
  CIATime := 0D;
END ResetTimer;

PROCEDURE Wait(msec : LONGCARD);
BEGIN
  CIATime := 0D;
  REPEAT UNTIL CIATime >= msec;
END Wait;

PROCEDURE IncTimer(): LONGCARD; (* Private: Not exported *)
BEGIN
  INC(CIATime);
  RETURN 0D;
END IncTimer;

PROCEDURE CreateTimer(): BOOLEAN;
BEGIN
  WITH timer DO
    isNode.lnType := NTInterrupt;
    isNode.lnPri := BYTE(0);
    isNode.lnName := ADR("PrivateCIATimerCIAicrTB");
    isData := ADR(CIATime);
    isCode := ADR(IncTimer);
  END; (* WITH *)

  CIAResource := OpenResource(ADR(CIAAName));

  IF CIAResource = NIL THEN
    WriteString("OpenCIAResource Failed.\n");
    RETURN FALSE;
  END;

  oldint :=  AddICRVector(CIAicrTB,timer,CIAResource^);
  IF oldint # NIL THEN (* Not available? Take it by force! *)
    RemICRVector(CIAicrTB,oldint^,CIAResource^);
    IF AddICRVector(CIAicrTB,timer,CIAResource^) # NIL THEN (* Install ours *)
      WriteString("AddICRVector Failed.\n");(*What?! This should never happen*)
      oldint := AddICRVector(CIAicrTB,oldint^,CIAResource^);
      CIAResource := NIL; (* So DeleteTimer will do nothing. *)
      RETURN FALSE;
    END; (* IF *)
  END; (* IF *)

  WITH ciaa^ DO             (* Using Timer B *)
    oldciacrb  := ciacrb;   (* Save the old so we can restore later *)
    oldciatblo := ciatblo;
    oldciatbhi := ciatbhi;
    ciacrb  := TIMEROFF;    (* Turn off Timer B *)
    ciatblo := LATCHLOW;    (* Set timer latch to 0x2CC (716) *)
    ciatbhi := LATCHHIGH;   (* to give us 1000hz resolution *)
    ciacrb  := TIMERON;     (* Turn on Timer B *)
  END; (* WITH ciaa^ *)

  RETURN TRUE;

END CreateTimer;

PROCEDURE DeleteTimer;
BEGIN
  IF CIAResource # NIL THEN
    ciaa^.ciacrb := TIMEROFF; (* Turn off Timer B *)
    RemICRVector(CIAicrTB,timer,CIAResource^); (* Remove our timer interrupt *)
    WITH ciaa^ DO            (* Restore old cia values so the disk drives *)
      ciatblo := oldciatblo; (* will work [nice feature]. *)
      ciatbhi := oldciatbhi;
      ciacrb  := oldciacrb;
    END; (* WITH *)
    (* Put back the old interrupt, this also sets the ICR bit and enAbles
       the corresponding bit interrupt, in this case Timer B [bit 1]. *)
    IF AddICRVector(CIAicrTB,oldint^,CIAResource^) # NIL THEN 
      WriteString("DANGER: Couldn't restore old CIAicrTB Vector!\n");
      WriteString("  Disk drives will now no longer function until\n");
      WriteString("  REBOOT!\n");   
    END;
  END;
END DeleteTimer;

BEGIN
  CIAResource := NIL;
END CIATimer.


  Here's what I'm trying to do:
    Wait with millisecond accuracy (has to be _accurate_), measure
response times with millisecond accuracy.
  This is being used for a research project, so I'm not worried
about multitasking, etc., but I'd like it to be "legal" if
possible [possibly just read system timers for stamps? Can I get high-res
accuracy (1ms), reliably?].
  The above works fine, >> as long as there are disks in all of the
drives and no disk access takes place <<.  
  What's the scoop?  What is the bottom line on these timers? Am I
reading the docs wrong, or is the documentation inaccurate?  
  Timer B on ciaa *should* be available.  I can't use timer A
because we need the serial port at the same time.
  I'd love to be enlightened on all of this...Any help appreciated.


  Thanks,


    John Schultz

riley@batcomputer.tn.cornell.edu (Daniel S. Riley) (12/29/88)

In article <38@sdcc10.ucsd.EDU> cs161agc@sdcc10.ucsd.edu.UUCP (John Schultz) writes:
[...code and other stuff deleted...]
>  Timer B on ciaa *should* be available.  I can't use timer A
>because we need the serial port at the same time.

Is this really true?  I know the hardware reference says "Commodore
Serial Communications", but SP and CNT for that CIA are connected to
paper out and busy on the parallel interface.  Those lines can be used
for serial communciation, but they have nothing to do with the serial
port, as far as I can tell.  Have you actually tried using timer A and
failed, or are you just trusting the somewhat misleading remarks in the
hardware reference?  Am I reading the Hardware reference right?  Is
time A actually used for anything?

-Dan Riley (dsr@lns61.tn.cornell.edu, cornell!batcomputer!riley)
-Wilson Lab, Cornell U.

dan@cbmvax.UUCP (Dan Baker CATS) (12/30/88)

In article <38@sdcc10.ucsd.EDU> cs161agc@sdcc10.ucsd.edu.UUCP 
(John Schultz) writes:
>
> [Long CIA timer program deleted....]
>
>  What's the scoop?  What is the bottom line on these timers? Am I
>reading the docs wrong, or is the documentation inaccurate?  
>  Timer B on ciaa *should* be available. 

CIA-A timer B is reserved for system use.  CIA-B timer B is available for 
applications.  The Hardware Manual is WRONG on this point.  Timers are
allocated as follows:                 -----

  CIA A  timer A  Used for keyboard handshake.
         timer B  Used for uSec timer.device.
         TOD      Used for 60 Hz timer.device.

  CIA B  timer A  Commodore 8-bit serial bus communication.  
         timer B  Not used.
         TOD      Used for graphics.library beam counter.

Use CIA-B timer B for your applications.  CIA-B timer A could also be used
although this is reserved for a "1541-style" interface for products like the
64-Emulator.  For more on this see Bob Burns' article in the Jan/Feb '89
issue of Amiga Mail coming soon.  Also see Paul Higginbottom's example
CIA timer porgram in the Sept/Oct '88 issue of Amiga Mail.
-- 
 Dan Baker, CATS

kodiak@amiga.UUCP (Robert R. Burns) (12/31/88)

In article ... (John Schultz) writes:
1) oldint :=  AddICRVector(CIAicrTB,timer,CIAResource^);
2) IF oldint # NIL THEN (* Not available? Take it by force! *)
3)   RemICRVector(CIAicrTB,oldint^,CIAResource^);
4)   IF AddICRVector(CIAicrTB,timer,CIAResource^) # NIL THEN (* Install ours *)
5)     WriteString("AddICRVector Failed.\n");(*What?! This should never happen*)

Unfortunately, there was no smiley face to calm me down.

Who is served in a multitasking environment by this kind of holier-than-thou,
stab-them-in-the-back programming mentality?  Certainly not the user!  The
Amiga has a few hardware resources which can be allocated by applications
that need them.  If they're already in use, do one of several things:
1.  Steal them, as above.  *No!*
2.  Die mysteriously.  *No!*
3.  Take the ln_Name of the oldint and present it to the user as an indication
    of what program precludes you from running.  *Yeah!*
    a.  *That's* why oldint was returned.
    b.  *That's* why filling in the ln_Name field of structures is useful.
    c.  *That way* the user is not mystified why one or the other of his
	applications went bust.

Remember multitasking!  See what happens when, between line 3 & line 4 above,
another task gets cycles and follows the rules?  Why *shouldn't* it happen?

Remember multitasking!  It imbues a special responsibility on Amiga
programmers to think harder and code better, so that one's goofs
do not cause another's application to appear buggy -- soiling the wrong
reputation.

- Kodiak
-- 
Bob Burns, amiga!kodiak                   _
| /_  _|. _ |      Commodore __          |_) _ |_  _ )'
|<(_)(_)|(_\|<      /\ |  ||| _` /\      |_)(_\| )(_\ |
| \ Software    ___/..\|\/|||__|/..\___           Faith

cs161agc@sdcc10.ucsd.EDU (John Schultz) (12/31/88)

In article <3227@amiga.UUCP> kodiak@tooter.UUCP (Robert Burns) writes:
>In article ... (John Schultz) writes:
[stuff I wrote deleted]
[100% USDA Certified Flames from Bob deleted]
>Unfortunately, there was no smiley face to calm me down.

  Ok, here's one now :-).

  But seriously, that code was written to be used in a *research*
experiment, by *no one else*.  More specifically, I was forced to
steal the timer because I had no other choice.  If I can't have a
millisecond timer, then we can't run the experiment.  I had to do
whatever necessary to get that timer.  Why did I steal it anyway?
The hardware manual was erroneous on the system's use of the timers.
Thanks to Dan Baker of CATS, I have the correct information as to
which timers are available.  Sorry I got you (Bob) all flustered, I
should have made the intended use clearer and stated what I was
doing was *totally illegal* for normal use.  But by golly I needed 
a timer and took the one the documentation said was available.  
  Anyway, I rewrote the code using CIA-B timer B and ran the
experiment [an Amiga talking to an HP which is controling a
Neuromagnetometer, making Magneto EncephaloGrams (MEG's) of human
brains [live, attached to people]].  Works wonderful.  And the code
is now fully *legal* and multitaskable.  This makes the Doctors
happy, which makes Me happy.
  I wonder what systems programmer's brain wave's look like
when they see code examples that "stab's them in the back"?  Better
not chance it, the temperature increase might cause the 
superconductors to heat up and blow out the MEG, spewing helium
everywhere.  We'd all talk funny for a week.
 
  Thanks Dan, Bob, for your interest,


  John Schultz