Magic Disk 64

home to index to text: MD9103-KURSE-CIA-KURS_TEIL_5-1_:_DIE_GEHEIMNISSE_DES_SECRET_SERVICE_(TEIL_5).txt
                CIA-Kurs:               
 "Die Geheimnisse des Secret Service..."
                (Teil 5)                

Hallo zusammen, zum 5 . Teil dieses Kurses. 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 versteht 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 erniedrigen - ich erwähnte Timer-Trigger schon zu Anfang dieses Kurses) .
Sie können in einen 16- Bit-Timer ja einen maximalen Wert von 2↑16-1=65535 laden. Bei 985248 .4 Taktzyklen, die der 64 er pro Sekunde bekommt, heißt das also, 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 einer 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 vorgegangen 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 einer CIA ausgelöst wird, wenn Timer B unterläuft, so hat man einen vollen 32- Bit-Zähler, mit dem wir schon ganz andere 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 zweiundvierzigmilliarden) Werte zählen, was bedeutet, daß wir auch dementsprechend lange Pausen zwischen zwei Timerinterrupts haben. Mal kurz durchgerechnet sind das alle 42949672955/985248 .2=4359 .273556 Sekunden. Das sind mehr als72 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 Problems nützlich sein. Ich habe mir da eine ganz sinnvolle Anwendung einfallen lassen und Ihnen gleich einmal ein Beispielprogramm 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 Taktzyklen 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 Zeiteinheiten, sprich Taktzylen, müssen wir nun einfach nur einen bestimmten Grundwert in beide Timer laden, sie starten und anschließend das zu prüfende Programm aufrufen. Dies wollen wir mittels eines " JSR"- Befehls tun. Springt das aufgerufene Programm nun zurück, so müssen 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, zwischen 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 aufgelistet, welche Möglichkeiten es hier gibt.
Timer B kann nämlich in Gegensatz zu Timer A vier ( anstelle von zweien) verschiedene Triggerquellen haben. Dies wird von den Bits 5 und 6 gesteuert, deren Kombinationen ich Ihnen noch einmal 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. Demnach 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 folgendermaß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 Ganzzahlanteil des Ergebnisses als höherwertiges Word. Dieses wird nun wie gewohnt in Lowund Highbyte aufgespalten.
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 niederwertige Word, das ebenfalls, wie gewohnt, in Lowund Highbyte umgewandelt wird.

Valid HTML 4.0 Transitional Valid CSS!