Magic Disk 64

home to index to html: MD9008-KURSE-ASSEMBLER-KURS_1_TEIL_8.html
        Assembler-Kurs Teil 8           
Der Stapel                              
----------                              
Der Stapel ist der  Speicherbereich  von
$0100 bis $01FF, 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 $01FF, das nächste in $01FE usw.
abgelegt wird.                          
Bemerkenswert ist beim  Stapel,  daß  er
nach  dem  LIFO-Prinzip  (last  in-first
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  keines-
falls eine der  unteren  Kisten  heraus-
ziehen  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  ($01FF
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.  Statt-
dessen 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ück-
   sprungadressen bei  Unterprogrammauf-
   rufen. 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 durch-
geführt wurden, zeigt  der  Stapelzeiger
SP auf  die  Speicherstelle  $01FF.  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  Stapel-
zeiger um 1 erniedrigt und zeigt so  auf
die  nächste  freie  Speicherstelle  des
Stapels  ($01FE).  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  Stapel-
zeiger 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  ge-
schobene 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  aus-
sagt, überträgt der Befehl  den  Stapel-
zeiger 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  er-
mö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änd-
lich  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  er-
folgte,  gemerkt.   Womit   wir   wieder
beim Stapel wären.                      
Der Prozessor muß also  vor  jeder  Ver-
zweigung  in   ein   Unterprogramm   die
momentane   Adresse   auf   den   Stapel
speichert,   was   der    Adresse    die
Instruktion  nach  dem  JSR-Befehl  ent-
spricht. 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  Stapel-
zeiger 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  umge-
kehrte  Prozess  ab.  Zuerst  wird   der
Stapelzeiger um 1 erhöht und das nieder-
wertige  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   Stapel-
bereich belegen, den auch  der  Program-
mierer  zur  vorübergehenden  Datenspei-
cherung benutzen kann. Da der  Speicher-
bereich 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!