Magic Disk 64

home to index to html: MD9103-KURSE-CIA-KURS_TEIL_5-1_:_DIE_GEHEIMNISSE_DES_SECRET_SERVICE_(TEIL_5).html
                CIA-Kurs:               
 "Die Geheimnisse des Secret Service..."
                (Teil 5)                
----------------------------------------
Hallo zusammen, zum 5. Teil dieses  Kur-
ses.  Nachdem  Sie nun ja ausgiebig über
Interrupts Bescheid wissen,  wollen  wir
uns  diesen  Monat noch einmal ein wenig
intensiver um die  CIA-Bausteine  ansich
kümmern,  denen  dieser Kurs ja gewidmet
ist.                                    
Diesmal wollen wir nämlich das Thema der
Timerkopplung  behandeln.  Darunter ver-
steht man die Verkettung von Timer A und
Timer B einer CIA zu einem großen 32-Bit
Timer (je ein Timer verfügt ja  über  je
16 Bit).                                
Wozu das gut ist, werden Sie  spätestens
dann gemerkt haben, als Sie einmal einen
Timer-Interrupt  programmieren  wollten,
der weniger oft als 15 mal  pro  Sekunde
auftritt.  Dann  reicht  nämlich ein 16-
Bit-Timer nicht mehr  aus,  insofern  er
Systemtakte zählt, was ja eigentlich die
häufigste Anwendung der Timer-Triggerung
ist  (Triggerung  gibt  den  auslösenden
Faktor an, der den Timer dazu veranlaßt,
den Wert, den er beinhaltet um 1 zu  er-
niedrigen  -  ich erwähnte Timer-Trigger
schon zu Anfang dieses Kurses).         
Sie  können in einen 16-Bit-Timer ja ei-
nen maximalen Wert von 2↑16-1=65535  la-
den.  Bei  985248.4  Taktzyklen, die der
64er pro Sekunde bekommt, heißt das  al-
so,  daß der Timer genau 985248.4/65535=
15.03392691 mal pro Sekunde  unterlaufen
kann,  wenn  er  am  langsamsten  läuft.
Langsamer (oder besser: weniger  häufig)
geht es nicht.                          
Zu diesem Zweck besteht  nun  aber  auch
die  Möglichkeit Timer A und Timer B ei-
ner CIA zu koppeln. Öber Timer B  hatten
wir  bisher  ja  wenig gesprochen, da er
vom Betriebssystem sowohl in  CIA1,  als
auch  in CIA2 nicht benutzt wird. Jedoch
ist es ebenso möglich ihn als  Timer  zu
verwenden,  wobei analog zu Timer A vor-
gegangen wird.                          
Nun jedoch zu jener  Kopplung.  Es  gibt
nämlich  eine  Möglichkeit,  mit der wir
Timer B anstelle  von  Systemtakten  die
Unterläufe  von  Timer  A  zählen lassen
können. Das heißt  also,  daß  jedesmal,
wenn Timer A bei 0 angekommen ist, Timer
B um 1 erniedrigt wird. Schaltet man nun
einen  Interrupt so, daß er dann von ei-
ner CIA ausgelöst  wird,  wenn  Timer  B
unterläuft,  so hat man einen vollen 32-
Bit-Zähler, mit dem wir schon ganz ande-
re  Dimensionen in Sachen Häufigkeit von
Unterläufen erreichen können. Mit 32 Bit
können  wir  nämlich   maximal   2↑32-1=
42949672995  (in  Worten:  über zweiund-
vierzigmilliarden)  Werte  zählen,   was
bedeutet,  daß  wir auch dementsprechend
lange Pausen zwischen  zwei  Timerinter-
rupts  haben.  Mal  kurz  durchgerechnet
sind  das  alle  42949672955/985248.2  =
4359.273556  Sekunden. Das sind mehr als
72 Minuten, also eine ganze Menge!      
Die dabei anfallenden Interrupts  werden
dann  von Timer B ausgelöst, weshalb wir
dann auch darauf achten müssen, das  wir
ihn als Interruptquelle im ICR (Register
13) setzen.                             
Kommen  wir  nun zu einer Anwendung. Ich
muß gestehen, viele Möglichkeiten hierzu
bieten sich  mir  nicht,  jedoch  könnte
eine  Timerkopplung  durchaus zur Lösung
des einen oder anderen  speziellen  Pro-
blems  nützlich  sein.  Ich  habe mir da
eine ganz sinnvolle Anwendung  einfallen
lassen  und Ihnen gleich einmal ein Bei-
spielprogramm vorbereitet, anhand dessen
ich Ihnen  die  Timerkopplung  erläutern
möchte. Es ist ein kleines Programm, das
den   Takzyklenverbrauch  eines  anderen
Programms stoppen kann.  Es  heißt  EVAL
und  ist auf dieser MD in zwei Versionen
gespeichert. Zum einen habe ich  da  den
ausführbaren Code, den Sie absolut laden
müssen  (mit  ",8,1") und der ab Adresse
$9000 (dez.36864) gestartet wird. Hierzu
jedoch später mehr.  Desweiteren  finden
Sie  auch  noch  den Quell-Code von EVAL
unter dem Namen "EVAL.SRC". Er  ist  wie
immer  im Hypra-Ass-Format und kann auch
ohne HYPRA-ASS mit ",8" zum Anschauen in
den Basicspeicher geladen werden.       
Doch nun zu EVAL selbst. Zunächst einmal
wollen wir uns  fragen,  was  nun  genau
geleistet   werden   soll.   EVAL   soll
zunächst einmal ganz einfach die Taktzy-
klen  zählen,  die  ein anderes Programm
verbraucht. Das ist die Problemstellung.
Die Lösung wollen wir -na, Sie werden es
nicht glauben- über die Timer einer  CIA
bewerkstelligen.   Ich  habe  zu  diesem
Zweck die CIA2 ausgesucht,  deren  Timer
normalerweise,    solange   die   RS232-
Schnittstelle  des  C64  nicht   genutzt
wird, unbenutzt sind.                   
Zur  Ermittlung  der  verstrichenen Zei-
teinheiten, sprich Taktzylen, müssen wir
nun einfach nur einen bestimmten  Grund-
wert  in  beide Timer laden, sie starten
und anschließend das  zu  prüfende  Pro-
gramm  aufrufen. Dies wollen wir mittels
eines  "JSR"-Befehls  tun.  Springt  das
aufgerufene Programm nun zurück, so müs-
sen wir den Timer  direkt  anhalten  und
anschließend den in ihm enthaltenen Wert
von unserem Anfangswert subtrahieren.   
Dadurch  erhalten  wir  die  Anzahl  der
Taktztyklen, die verstrichen sind,  zwi-
schen Start und Stop des Timers.        
Soviel zum theoretischen  Programmablauf
von  EVAL.  Kommen wir nun zu den Timern
selbst. Zunächst müssen wir zusehen, daß
wir eine richtige Triggerung für Timer A
und Timer B wählen. Timer B soll ja  die
Unterläufe von Timer A zählen und dieser
widerum die Systemtakte. Zu diesem Zweck
schreiben  wir also erst einmal den Wert
$81 in das Control-Register von Timer  A
(=CRA,  Reg.14),  wie  wir  das  ja auch
schon  von  der  Interruptprogrammierung
her  kennen.  Weil bei diesem Wert Bit 5
gelöscht ist zählt Timer A also  System-
takte.                                  
Für  Timer B wird das schon schwieriger.
Ich hatte Ihnen ja schon einmal bei  der
Beschreibung  der  CIA-Register aufgeli-
stet, welche Möglichkeiten es hier gibt.
Timer B kann  nämlich  in  Gegensatz  zu
Timer  A vier (anstelle von zweien) ver-
schiedene  Triggerquellen  haben.   Dies
wird  von  den  Bits  5 und 6 gesteuert,
deren Kombinationen ich Ihnen noch  ein-
mal auflisten möchte:                   
Bit 5 6  Timer B zählt...               
----------------------------------------
    0 0  Systemtakte.                   
    0 1  steigende CNT-Flanken.         
    1 0  Unterläufe von Timer A.        
    1 1  Unterläufe von Timer A, wenn   
         CNT=1 ist.                     
Für uns kommt da die Kombination "10" in
Frage.  Bit  5 ist also gesetzt und alle
anderen gelöscht. Wie bei Timer A müssen
wir jedoch auch Bit 0 setzen,  weil  wir
beim Laden dieses Wertes in das Control-
Register von Timer B (CRB,  Reg.15)  den
Timer  auch  gleich starten wollen. Dem-
nach brauchen wir diesmal den Wert $41. 
Das war dann auch schon alles,  was  wir
zur   Timerkopplung  brauchen.  Timer  A
zählt nun Systemtakte und löst bei jedem
Unterlauf ein Herabzählen  von  Timer  B
aus.  Einen Interrupt wollen wir diesmal
nicht erzeugen,  doch  könnte  man  auch
durchaus  im  ICR  festlegen,  das einer
erzeugt werden soll, wenn Timer  B  dann
unterläuft.                             
Somit hätten wir also einen 32-Bit Timer
der Systemtakte zählt.  Die  Reihenfolge
der LO/HI-Zählbytes sieht nun folgender-
maßen aus:                              
TimerB-HI TimerB-LO TimerA-HI TimerA-LO 
Sie müssen also nicht nur ein  High  und
Lowbytepaar  berechnen,  sondern  gleich
zwei. Hier wechselt man dann auch in die
nächsthöhere Ebene der "Bits und Bytes".
Eine 16-Bit-Zahl bezeichnet man  nämlich
als  ein "Word" (engl.: wörd = Wort) und
eine 32-Bit-Binärzahl als ein "Longword"
(engl.: Langwort). Um  eine  Dezimalzahl
nun  in  ein Longword umzuwandeln müssen
Sie folgendermaßen vorgehen:            
1) Zunächst teilen wir unsere Zahl durch
   2↑16 (=65536) und nehmen den Ganzzah-
   lanteil des Ergebnisses als höherwer-
   tiges  Word.  Dieses wird nun wie ge-
   wohnt in Low- und Highbyte aufgespal-
   ten.                                 
2) Nun  multiplizieren wir das High-Word
   mit 2↑16 und subrahieren den Wert von
   unserem Anfangswert. Das Ergebnis was
   wir hier erhalten ist das  niederwer-
   tige  Word,  das  ebenfalls,  wie ge-
   wohnt, in Low- und Highbyte  umgewan-
   delt wird.                           
Valid HTML 4.0 Transitional Valid CSS!