Assembly Language
Stos
Szukaj…
Uwagi
Stos komputerów jest jak stos książek. PUSH dodaje jeden do góry, a POP zabiera go najwyżej. Tak jak w prawdziwym życiu, stos nie może być nieograniczony, więc ma maksymalny rozmiar. Stosu można używać do algorytmów sortowania, do obsługi większej ilości danych lub do bezpiecznych wartości rejestrów podczas wykonywania innej operacji.
Zilog Z80 Stack
Rejestr sp
służy jako wskaźnik stosu , wskazując na ostatnią zapisaną wartość na stos („góra” stosu). EX (sp),hl
zamieni wartość hl
z wartością na szczycie stosu.
W przeciwieństwie do słowa „górnego” stos rośnie w pamięci, zmniejszając sp
, i zwalnia wartości („wyskakuje”), zwiększając sp
.
Dla sp
= $4844
z wartościami 1
, 2
, 3
przechowywanymi na stosie ( 3
są wypychane na stos jako ostatnia wartość, więc znajdują się na szczycie), pamięć będzie wyglądać następująco:
| 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
Przykłady, w jaki sposób instrukcje działają ze stosem:
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
Podsumowanie : PUSH
zapisze wartość na górze stosu, POP
pobierze wartość z góry stosu, jest to kolejka LIFO (ostatnia, pierwsza wyszła). CALL
jest taki sam jak JP
, ale przesuwa również adres następnej instrukcji po CALL
na górze stosu. RET
jest również podobny do JP
, usuwając adres ze stosu i przechodząc do niego.
Ostrzeżenie : gdy włączone są przerwania, sp
musi być ważne podczas sygnału przerwania, z wystarczającą ilością wolnego miejsca zarezerwowanego dla procedury obsługi przerwań, ponieważ sygnał przerwania zachowa adres zwrotny (rzeczywisty pc
) przed wywołaniem procedury obsługi, która może przechowywać dalsze dane na stos. Każda wartość wyprzedzająca sp
może być zatem zmodyfikowana „nieoczekiwanie”, jeśli nastąpi przerwanie.
Zaawansowana sztuczka : w Z80 z PUSH
pobierającym 11 cykli zegara (11t) i POP
pobierającym 10t, rozwinięty POP
/ PUSH
przez wszystkie rejestry, w tym EXX
dla wariantów cienia, był najszybszym sposobem na skopiowanie bloku pamięci, nawet szybciej niż rozwinięty LDI
. Ale trzeba było kopiować pomiędzy sygnałami przerwania, aby uniknąć uszkodzenia pamięci. Również rozwinięty PUSH
był najszybszym sposobem na wypełnienie pamięci szczególną wartością w ZX Spectrum (ponownie z ryzykiem uszkodzenia przez Przerwanie, jeśli nie jest odpowiednio ustawione w czasie lub wykonane w DI
).