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 Assemblerroutine sowieso nicht sein.
Kommen wir nun also zu der Programmierung von EVAL. Hier möchte ich Ihnen
einmal den Anfang des Programms auflisten:
------------------- 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 Interruptquellen durch Löschen des ICR. Anschließend
werden durch das Schreiben von 0 in die
Control-Register der Timer selbige gestoppt. 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. Hierbei 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üssen 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 einige Taktzyklen die EVAL benötigt.
Im letzten Teil wird nun noch die zu
testende Routine aufgerufen, die ich
hier einmal bei $ C000( dez.49152) angesiedelt 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 Taktzyklus der dabei verstreicht wird mitgezä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 Timerregistern logischerweise haargenau die
Anzahl der verbrauchten Taktzyklen stehen, jedoch in einem invertierten Format. Das heißt, daß dadurch, daß der
Timer rückwärts lief, die Taktzyklenanzahl mit folgender Formel berechnet werden 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 absoluten Maximalwert in die Timer geladen
hatten, können wir diese Umrechnung
durch schlichtes invertieren der einzelnen Bytes vornehmen. Dabei wird das sogenannte 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 dieses Werts mittels des " EOR"- Befehls
ergäbe dann:$00$00$00$00- mit anderen 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 Ergebniszahl 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 absolute 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 nacheinander 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üssen, damit Sie einen Sinn ergeben. Das
hat aber auch noch einen anderen, weitaus wichtigeren Grund:
Ich habe die Adressen $62-$65 nämlich
nicht etwa willkülich als Zwischenspeicher gewählt, sondern in diesen Adressen
befinden sich nämlich die Mantissenbytes
des Floatingpoint-ACcumualtors ( kurz:
" FAC") des 64 ers. Damit wir unsere 32- Bit-Zahl nämlich auch richtig in dezimaler Schreibweise ausgeben können, brauchen wir nämlich den FAC. Der FAC ist
ein bestimmter Speicherbereich in der
Zeropage der vom Betriebssystem dazu
genutzt wird, Fließkommazahlen aufzunehmen und mit ihnen herumzurechnen. Ebenso
gibt es auch eine Routine des Betriebssystems, mit deren Hilfe wir die
32- Bit-Zahl nachher in Dezimalschreibweise umwandeln, um sie ausgeben zu können. Dazu jedoch später.
Zunächst einmal hätten wir also die absolute Anzahl der vergangenen Taktzyklen, 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 verbraucht wurden, in unserer Rechnung. WO?
Werden Sie jetzt fragen, na ganz einfach
- schauen wir uns nocheinmal die Zeilen
vor und hinter dem Aufruf des Testprogramms 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.
-------------------
. . .