Assembly Language
Der Stapel
Suche…
Bemerkungen
Der Stapel von Computern ist wie ein Stapel Bücher. PUSH fügt eins hinzu und POP nimmt den obersten weg. Wie in der Praxis kann der Stapel nicht endlos sein, also maximal groß sein. Der Stapel kann für Sortieralgorithmen verwendet werden, um eine größere Datenmenge zu verarbeiten oder um Werte von Registern zu sichern, während eine andere Operation ausgeführt wird.
Zilog Z80 Stack
Das Register sp
wird als Stackzeiger verwendet und zeigt auf den letzten gespeicherten Wert im Stack ("top" of stack). Also wird EX (sp),hl
den Wert von hl
mit dem Wert oben auf dem Stapel austauschen.
Im Gegensatz zu dem Wort "top" wächst der Stapel im Speicher durch Verringerung der sp
und gibt ("Pops") Werte durch Erhöhung von sp
.
Für sp
= $4844
mit den Werten 1
, 2
, 3
die im Stapel gespeichert sind (die 3
wird als letzter Wert auf den Stapel geschoben, also ganz oben), sieht der Speicher folgendermaßen aus:
| address | value bytes | comment (btw, all numbers are in hexadecimal)
| ---------- | ----------- | ---------------------------------
| 4840 | ?? ?? | free stack spaces to be used by next push/call
| 4842 | ?? ?? | or by interrupt call! (don't expect values to stay here)
| sp -> 4844 | 03 00 | 16 bit value "3" on top of stack
| 4846 | 02 00 | 16 bit value "2"
| 4848 | 01 00 | 16 bit value "1"
| 484A | ?? ?? | Other values in stack (up to it's origin)
| 484C | ?? ?? | like for example return address for RET instruction
Beispiele, wie Anweisungen mit Stack arbeiten:
LD hl,$0506
EX (sp),hl ; $0003 into hl, "06 05" bytes at $4844
POP bc ; like: LD c,(sp); INC sp; LD b,(sp); INC sp
; so bc is now $0506, and sp is $4846
XOR a ; a = 0, sets zero and parity flags
PUSH af ; like: DEC sp; LD (sp),a; DEC sp; LD (sp),f
; so at $4844 is $0044 (44 = z+p flags), sp is $4844
CALL $8000 ; sp is $4842, with address of next ins at top of stack
; pc = $8000 (jumping to sub-routine)
; after RET will return here, the sp will be $4844 again
LD (L1+1),sp ; stores current sp into LD sp,nn instruction (self modification)
DEC sp ; sp is $4843
L1 LD sp,$1234 ; restores sp to $4844 ($1234 was modified)
POP de ; de = $0044, sp = $4846
POP ix ; ix = $0002, sp = $4848
...
...
ORG $8000
RET ; LD pc,(sp); INC sp; INC sp
; jumps to address at top of stack, "returning" to caller
Zusammenfassung : PUSH
speichert den Wert auf dem Stapel, POP
holt den Wert vom Stapel, es ist eine LIFO- Warteschlange (Last In, First Out). CALL
ist dasselbe wie JP
, schiebt jedoch nach CALL
die Adresse des nächsten Befehls an den Anfang des Stapels. RET
ist ähnlich wie JP
, springt die Adresse aus dem Stapel und springt zu ihm.
Warnung : Wenn Interrupts aktiviert sind, muss der sp
während des Interruptsignals gültig sein, und es muss ausreichend freier Speicherplatz für die Interrupt-Handler-Routine reserviert werden, da das Interrupt-Signal die Rücksprungadresse (den aktuellen pc
) vor dem Aufruf der Handler-Routine speichert, in der weitere Daten gespeichert werden können auch stapeln. Jeder Wert vor sp
kann daher "unerwartet" geändert werden, wenn ein Interrupt auftritt.
Fortgeschrittener Trick : Bei Z80 mit PUSH
mit 11 Taktzyklen (11t) und POP
mit 10t war der POP
/ PUSH
EXX
durch alle Register, einschließlich EXX
für Schattenvarianten, der schnellste Weg, Speicherblöcke zu kopieren, sogar noch schneller als abgewickelter LDI
. Sie mussten jedoch die Kopie zwischen den Interrupt-Signalen zeitlich festlegen, um eine Beschädigung des Speichers zu vermeiden. Auch das Aufrollen von PUSH
war der schnellste Weg, um Speicher mit besonderem Wert auf ZX Spectrum aufzufüllen (wiederum mit der Gefahr von Korruption durch Interrupt, falls nicht ordnungsgemäß zeitgesteuert oder unter DI
).