Magic Disk 64

home to index to text: MD9103-KURSE-CIA_KURS_TEIL_5-2.txt

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.
------------------- . . .

Valid HTML 4.0 Transitional Valid CSS!