Assembly Language
Stacken
Sök…
Anmärkningar
Bunten med datorer är som en bunt böcker. PUSH lägger till en till toppen och POP tar det översta bort. Liksom i verkligheten kan stacken inte vara oändlig, så den har maximal storlek. Bunten kan användas för att sortera algoritmer, för att hantera en större mängd data eller för att säkra värden på register medan du gör en annan operation.
Zilog Z80 Stack
Registret sp
används som stackpekaren och pekar på det senast lagrade värdet i stacken ("toppen" av stacken). Så EX (sp),hl
att byta värde på hl
med värdet ovanpå stacken.
I motsats till "översta" ordet växer stacken i minnet genom att minska sp
och släpper ("pops") värden genom att öka sp
.
För sp
= $4844
med värden 1
, 2
, 3
lagrade på bunten (de 3
skjuts på bunten som sista värde, så att vara överst på det) kommer minnet att se ut så här:
| 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
Exempel på hur instruktioner fungerar med stack:
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
Sammanfattning : PUSH
kommer att lagra värde på toppen av stacken, POP
hämtar värde från toppen av stacken, det är en LIFO (sist in, först ut) kö. CALL
är samma som JP
, men det trycker också på adressen till nästa instruktion efter CALL
överst i bunten. RET
liknar JP
också, hoppar adressen från stacken och hoppar till den.
Varning : när avbrott är aktiverat måste sp
vara giltigt under avbrottssignal, med tillräckligt med ledigt utrymme reserverat för avbrottshanteringsrutin, eftersom avbrottssignalen kommer att lagra returdressen (faktiska pc
) innan den ringer hanterarutin, vilket kan lagra ytterligare data på stack också. Alla värden före sp
kan således ändras "oväntat", om avbrott inträffar.
Avancerat trick : på Z80 med PUSH
tar 11 klockcykler (11t) och POP
tar 10t, var det orullade POP
/ PUSH
genom alla register, inklusive EXX
för skuggvarianter, det snabbaste sättet att kopiera minnesblock, ännu snabbare än orullad LDI
. Men du var tvungen att ställa in kopian mellan avbrottssignaler för att undvika minneskorruption. Ovalsad PUSH
var också det snabbaste sättet att fylla minnet med särskilt värde på ZX Spectrum (återigen med risken för korruption av Interrupt, om inte tidsinställd korrekt, eller gjort under DI
).