Als Beispiel habe ich einmal die Zahl 2000000 in ein Langword umgewandelt:
1 ) 2000000/65536=30.51757813 1a) HI-Word=30 --> LO=30, HI=0 2 ) 2000000-30*65536=33920 2a) LO-Word=33920 --> LO=128, HI=132
Longword: ---------
0 30 132 128 Binär: ------ 00000000 00011110 10000100 10000000
Soviel also hierzu. Nun können wir also schon einmal beliebig lange 32-Bit- Timerwerte berechnen. Für EVAL habe ich übrigens nicht irgendeine Zahl genommen, sondern schlichtweg die größte (also die 42 Milliarden von oben). Länger als 72 Minuten sollte eine zu testende Assem- blerroutine sowieso nicht sein. Kommen wir nun also zu der Programmie- rung von EVAL. Hier möchte ich Ihnen einmal den Anfang des Programms aufli- sten:
------------------- EVAL LDA #$7F Zunächst alle Inter- STA CIA2+13 rupts sperren. LDA #00 Und... STA CIA2+14 Timer A und STA CIA2+15 Timer B anhalten. ------------------- LDA #$FF Nun den Maximalwert STA CIA2+4 in Timer A STA CIA2+5 und STA CIA2+6 in Timer B STA CIA2+7 schreiben. ------------------- LDA #$41 Timer B soll Timer A STA CIA2+15 zählen LDA #$81 Timer A soll System- STA CIA2+14 takte zählen. -------------------
JSR $C000 Testprogramm aufrufen
-------------------
Im ersten Teil dieses Listings sperren wir zunächst einmal alle Interruptquel- len durch Löschen des ICR. Anschließend werden durch das Schreiben von 0 in die Control-Register der Timer selbige ge- stoppt. Diese Maßnahmen sind nur für den Fall gedacht, daß in diesen Timern ganz gegen unsrer Erwartung doch etwas laufen sollte. Zum korrekten Ablauf von EVAL ist es absolut notwenidig, daß die Timer stehen, da sonst die Testwerte verfälscht würden. Anschließend werden die Register TALO, TAHI, TBLO, TBHI mit dem Wert 255 (=$FF) geladen und so auf den Maximalwert 2↑32-1 gesetzt. Im dritten Teil des Listings werden nun die beiden Timer wieder gestartet. Hier- bei MUß Timer B unbedingt VOR Timer A aktiviert werden, da er zum Einen von diesem abhängig ist, und deshalb zuerst aktiv sein sollte (würde Timer A nämlich unterlaufen BEVOR Timer B zählbereit ist, wäre das Testergebnis ebenfalls nicht in Ordnung), und zum Anderen müs- sen wir so spät wie möglich den 32-Bit- Timer starten, damit auch tatsächlich die Taktzyklen der zu messenden Routine gezählt werden und nicht etwa noch eini- ge Taktzyklen die EVAL benötigt. Im letzten Teil wird nun noch die zu testende Routine aufgerufen, die ich hier einmal bei $C000 (dez.49152) ange- siedelt habe. Jetzt ist also unser 32-Bit-Timer aktiv und zählt schön brav von 4294967295 Richtung 0 hinab. Währenddessen läuft unser Testprogramm ab und jeder Taktzy- klus der dabei verstreicht wird mit- gezählt. Wird das Programm dann mittels "RTS" beendet, so kehrt der Rechner wieder in EVAL zurück. Nun müssen wir uns um die weitere Behandlung der Timer kümmern. Damit wieder keine unnötige Rechnerzeit mitgezählt wird stoppen wir also zunächst beide Timer:
------------------- LDA #$80 Wert für "Timer-Stop" STA CIA2+14 Timer A und STA CIA2+15 Timer B anhalten. -------------------
Da der unser 32-Bit-Timer nun also nur während des Ablaufs des zu testenden Programms lief, müsste nun in den Timer- registern logischerweise haargenau die Anzahl der verbrauchten Taktzyklen ste- hen, jedoch in einem invertierten For- mat. Das heißt, daß dadurch, daß der Timer rückwärts lief, die Taktzyklenan- zahl mit folgender Formel berechnet wer- den muß: (2↑32-1)-(Longword in Timerregistern)= tatsächlich verbrauchte Taktzyklen. Na aber holla, das könnte ja schwer wer- den, die 4-Byte Werte voneinander zu subtrahieren! Doch keine Panik, auch das läßt sich ganz einfach lösen. Dadurch nämlich, daß wir beim Start den absolu- ten Maximalwert in die Timer geladen hatten, können wir diese Umrechnung durch schlichtes invertieren der einzel- nen Bytes vornehmen. Dabei wird das so- genannte Einerkomplement unserer Zahl gebildet, was ebenfalls eine Art ist, Bytes voneinander zu subtrahieren. Zum Beweis möchte ich Ihnen hier einmal ein Beipiel geben: Wir hatten den Startwert $FF $FF $FF $FF im Timer stehen. Eine Invertierung die- ses Werts mittels des "EOR"-Befehls ergäbe dann: $00 $00 $00 $00 - mit ande- ren Worten, der Startwert war 0. Angenommen, nun war der Wert, den wir nach Ablauf eines Testprogramms in den Timern vorfanden folgender: $FF $FD $03 $AE. Dies entspricht dem Dezimalwert 4294771630. Subrtrahieren wir diesen Wert von 2↑32-1, so ergibt sich folgendes Ergebnis: 195665. Das wäre also die Anzahl der Taktzyklen, die das aufgerufene Programm verbrauchte. Nun wollen wir doch testweise einfach einmal das Einerkomplement der Ergebnis- zahl bilden (ebenfalls mittels "EOR"):
$FF $FD $03 $AE --> $00 $02 $FC $51.
Dieses Longword umgerechnet ergibt nun aber ebenfalls die Zahl 195665 - "quod erat demonstandum!" Kommen wir nun also zum nächsten Teil von EVAL, dem Retten der Timerwerte und dem gleichzeitigen Umwandeln in die ab- solute Zahl an Taktzyklen:
------------------- LDY #03 Quellzähler initia- lisieren. LDX #00 Zielzähler initiali- sieren. LOOP1 LDA CIA2+4,Y Akku mit dem hinter- sten Timerregister laden EOR #$FF Komplement bilden STA $62,X und umgekehrt si- chern. INX Zielzähler +1. DEY Quellzähler -1. BPL LOOP1 Wenn noch nicht un- tergelaufen, dann wiederholen. -------------------
Diese Schleife nimmt sich nun nacheinan- der die CIA-Register 7,6,5 und 4 vor, bildet ihr Komplement und speichert sie umgekehrt in die Zeropageadressen $62, $63, $64 und $65. Damit hätten wir dann auch gleichzeitig das Problem gelöst, daß die Bytes ja in der Reihenfolge TBHI TBLO TAHI TALO aufeinander folgen müs- sen, damit Sie einen Sinn ergeben. Das hat aber auch noch einen anderen, wei- taus wichtigeren Grund: Ich habe die Adressen $62-$65 nämlich nicht etwa willkülich als Zwischenspei- cher gewählt, sondern in diesen Adressen befinden sich nämlich die Mantissenbytes des Floatingpoint-ACcumualtors (kurz: "FAC") des 64ers. Damit wir unsere 32- Bit-Zahl nämlich auch richtig in dezima- ler Schreibweise ausgeben können, brau- chen wir nämlich den FAC. Der FAC ist ein bestimmter Speicherbereich in der Zeropage der vom Betriebssystem dazu genutzt wird, Fließkommazahlen aufzuneh- men und mit ihnen herumzurechnen. Ebenso gibt es auch eine Routine des Be- triebssystems, mit deren Hilfe wir die 32-Bit-Zahl nachher in Dezimalschreib- weise umwandeln, um sie ausgeben zu kön- nen. Dazu jedoch später. Zunächst einmal hätten wir also die ab- solute Anzahl der vergangenen Taktzy- klen, die zwischen Start und Stop des Timers verstichen sind im FAC stehen. Leider haben wir nun aber doch noch ei- nige Taktzyklen, die durch EVAL ver- braucht wurden, in unserer Rechnung. WO? Werden Sie jetzt fragen, na ganz einfach - schauen wir uns nocheinmal die Zeilen vor und hinter dem Aufruf des Testpro- gramms an:
... LDA #$81 Timer A soll System- STA CIA2+14 takte zählen. ------------------- JSR $C000 Testprgramm aufrufen. -------------------
LDA #$80 Wert für "Timer-Stop" STA CIA2+14 Timer A und STA CIA2+15 Timer B anhalten. ------------------- ...