Magic Disk 64

home to index to text: MD9406-KURSE-ASSEMBLER_KURS_2_(TEIL_8).txt

Assembler-Kurs Teil 8

Der Stapel                              

Der Stapel ist der Speicherbereich von $0100 bis $01 FF, der direkt von der CPU verwaltet wird. Der Zugriff auf diese " Page 1" ist daher sehr schnell.
Ein Stapel wächst von oben nach unten, d. h. in unserem Fall, daß zuerst ein Byte in $01 FF, das nächste in $01 FE usw.
abgelegt wird.
Bemerkenswert ist beim Stapel, daß er nach dem LIFO-Prinzip ( last infirst out) arbeitet. Das zuletzt auf den Stapel gebrachte Byte muß also als erstef wieder heruntergeholt werden, wenn die darunterliegenden Bytes gelesen werden sollen.
Wenn Sie Schwierigkeiten haben, sich das LIFO-Prinzip zu verdeutlichen, dann denken Sie sich den Stapel doch einfach als einen Stapel von Getränkekisten.
Dann wird Ihnen klar, daß Sie keinesfalls eine der unteren Kisten herausziehen können. Die zuletzt auf den Stapel gebrachte Kiste, das ist die Kiste ganz oben auf dem Stapel, muß als erste entfernt werden, um an die darunterliegende Kiste heranzukommen.
Aber woher weiß der Computer, welcher Wert auf dem Stapel der oberste ist?
Dazu benötigen wir einen Zeiger ( Pointer), der auf die jeweilige Spitze des Stapels zeigt, den sogenannten Stapelzeiger ( Stackpointer) . Unser Stapelzeiger ist 8 Bits breit, also eigentlich um ein Byte zu klein für die Adressierung des Stapelbereichs ($01 FF bis $0100) . Sicher fällt Ihnen auf, daß das höherwertige Byte ($01) über dem gesamten Stapelbereich gleich bleibt. Es ist daher unnötig, diesen Wert immer im Stapelzeiger mit abzuspeichern. Stattdessen begnügt man sich damit, daß der Stapelzeiger das niederwertige Byte der Spitze des Stapels enthält.
Die effektive Adresse, auf die der Zeiger deutet, kann man sich folglich mit $0100+( Inhalt des Stapelzeigers) selbst errechnen.
Gültige Werte sind für den Stapelzeiger zwischen $00 und $ FF.
So, jetzt wissen wir, wie ein Stapel funktioniert, aber wozu man einen Stapel benötigt, das wissen wir noch nicht.
Es gibt drei wichtige Anwendungsgebiete für einen Stapel:
1 . Er übernimmt die Verwaltung der Rücksprungadressen bei Unterprogrammaufrufen. Diese Eigenschaft wird später noch näher erläutert werden.
2 . Zur Zwischenspeicherung von Daten bei Interrupts.
3 . Kurzzeitige Sicherung von Daten.
Diesen letzte Punkt wollen wir uns nun genau ansehen.

Die Stapeloperationen                   

Im Grunde genommen benötigt man nur zwei verschiedene Stapelbefehle, nämlich einen, um etwas auf den Stapel zulegen ( PUSH) und einen, um einen Wert vom Stapel zu holen ( PULL, POP) .

Stapel        nach PUSH      nach PUSH  
vorher:       Wert1:         Wert2:     
$01FD |  |       |  |        |  |<-SP   
      |  |       |--|        |--|       
$01FE |  |       |  |<-SP    |W2|       
      |--|       |--|        |--|       
$01FF |  |<-SP   |W1|        |W1|       
      ----       ----        ----       

Wenn noch keine Stapeloperationen durchgeführt wurden, zeigt der Stapelzeiger SP auf die Speicherstelle $01 FF. Nun wird WERT1 auf den Stapel gelegt, und zwar an der Adresse, auf die der Stapelzeiger weist. Nach diesem Schreib- zugriff auf den Stapel wird der Stapelzeiger um 1 erniedrigt und zeigt so auf die nächste freie Speicherstelle des Stapels ($01 FE) . Eine weiters PUSH-Anweisung legt den WERT2 auf die Spitze des Stapels ( Top of Stack), was der Position des Stapelzeigers entspricht.
Anschließend erniedrigt sich der Stapelzeiger wieder um 1 .
nach PULL Wert2 : nach PULL Wert1 :

$01FD |  |            |  |              
      |  |            |--|              
$01FE |  |<-SP        |  |              
      |--|            |--|              
$01FF |W1|            |  |<-SP          
      ----            ----              

Während bei PUSH-Befehlen des Stapels zu beobachten war, daß sich der Stapelzeiger erst nach dem Schreiben in die Stapelspeicherstelle erniedrigt hat, stellt man nun fest, daß bei PULL- Anweisungen der Stapelzeiger vor dem Lesezugriff inkrementiert wird. Das ist auch nötig, da der Stapelzeiger immer auf die nächste FREIE Speicherstelle des Stapels zeigt. Wird der Stapelzeiger zuvor inkrementiert, dann weist er nun auf das zuletzt auf den Stapel geschobene Element. Dieser Wert kann nun vom Stapel geholt werden.
Das obige Beispiel verdeutlicht, daß der zuerst auf den Stapel gelegte Wert ( Wert1) erst als letzter vom Stapel geholt werden kann.
Die PUSH-Befehle

PHA (PusH Accumulator)                  

Mit diesem Befehl wird der Akkuinhalt auf den Stapel geschoben. Anschließend wird der Stapelzeiger um 1 erniedrigt.
Der Akkuinhalt bleibt dabei, ebenso wie die Flaggen, unverändert.

PHP (PusH Processor status)             

Anstelle des Akkuninhaltes wird jetzt das gesamte Statusregister des Prozessors mit allen Flaggen auf den Stapel gelegt.
Danach wird der Stapelzeiger um 1 erniedrigt.
Die PULL-Befehle

PLA (PuLl Accumulator)                  

Diese Anweisung ist das Gegenstück zu PHA. Der Stapelzeiger wird zuerst um 1 erhöht. Nun wird der Inhalt der Speicherstelle, auf die der Stapelzeiger deutet, in den Akku eingelesen. Neben dem Akkuinhalt können sich auch die Flaggen N und Z ändern.

PLP (PuLl Processor status)             

Der Stapelzeiger wird inkrementiert und der aktuelle Stapelwert wird in das Prozessor-Statusregister übertragen.
Dabei ändern sich selbstverständlich alle Flaggen.
Zusätzlich zu den Stapeloperationen gibt es auch noch zwei Transferbefehle, die sich direkt auf den Stapelzeiger beziehen.
Die Stapel-Transferbefehle

TSX (Transfer Stackpointer to X)        

Wie der Name der Anweisung schon aussagt, überträgt der Befehl den Stapelzeiger in das X-Register. Somit kann die Adresse, auf die der Stapelzeiger weist, ermittelt werden. Das X-Register kann dementsprechend Werte zwischen $00 und $ FF enthalten.

TXS (Transfer X to Stackpointer)        

Dieser gegenteilige Befehl zu TSX ermöglicht eine direkte Einflußnahme des Programmierers auf den Stapelzeiger, indem der Wert des X-Registers in den Stapelzeiger übertragen wird.
Alle oben genannten Befehle können nur impliziert adressiert werden, d. h. sie haben keinen Adressteil.

 Der Einsatz des Stapels bei Unterprg's 
 -------------------------------------- 

Bisher haben wir es als selbstverständlich erachtet, daß unser Assembler-Programm nach einem RTS bei der nächsten Anweisung nach dem JSR im aufrufenden Programm fortfährt.
Das Programm hat sich also die Stelle, von der aus der Unterprogrammsprung erfolgte, gemerkt. Womit wir wieder beim Stapel wären.
Der Prozessor muß also vor jeder Verzweigung in ein Unterprogramm die momentane Adresse auf den Stapel speichert, was der Adresse die Instruktion nach dem JSR-Befehl entspricht. Diese Adresse muß nach einer speziellen Regel " gestackt" werden, da unser Stapel bekanntlich immer nur ein Byte aufnehmen kann, eine Adresse jedoch aus 2 Bytes besteht. Zuerst wird das höherwertige Byte mit einem PUSH auf den Stapel gelegt und anschließend der Stapelzeiger um 1 vermindert. Erst jetzt wird das niederwertige Byte auf den Stapel gebracht. Erneut muß der Stapelzeiger dekrementiert werden.
Hauptprogramm Unterprogramm

       -----------                ----- 
      |     .     |     -> $C200 |  .  |
      |     .     |    |         |  .  |
$C100 | JSR $C200 | ---          |  .  |
$C103 |     .     | <----------- | RTS |
      |     .     |               ----- 

----------- Der Stapel nach JSR $ C200 :

      |   |<-SP                         
      |---|                             
$01FE |$03|                             
      |---|                             
$01FF |$C1|                             
      -----                             

Nach einem RTS-Befehl läuft der umgekehrte Prozess ab. Zuerst wird der Stapelzeiger um 1 erhöht und das niederwertige Byte vom Stapel geholt. Im Anschluß daran holt man das höherwertige Byte vom Stapel und der Stapelzeiger wird wieder erhöht. nun kann die aktuelle Adresse wieder zusammengesetzt werden und das Hauptprogramm fährt mit seiner Abarbeitung an der gewünschten Stelle fort.
Es fällt uns auf, daß diese abgelegten Rücksprung-Adressen denselben Stapelbereich belegen, den auch der Programmierer zur vorübergehenden Datenspeicherung benutzen kann. Da der Speicherbereich des Stapels begrenzt ist, müssen wir auch die Struktur dieser automatisch ablaufenden Prozesse der Unterprogramm-Verwaltung kennen.
( rt/ wk)

Valid HTML 4.0 Transitional Valid CSS!