Assembly Language
Стек
Поиск…
замечания
Стек компьютеров похож на стопку книг. PUSH добавляет один к вершине, а POP занимает верхнюю часть. Как и в реальной жизни, стек не может быть бесконечным, поэтому он имеет максимальный размер. Стек может использоваться для сортировки алгоритмов, для обработки большего количества данных или для безопасного значения регистров при выполнении другой операции.
Zilog Z80 Stack
Регистр sp
используется как указатель стека , указывая на последнее сохраненное значение в стек («верх» стека). Таким образом, EX (sp),hl
будет обменивать значение hl
со значением поверх стека.
Вопреки «верхнему» слову, стек растет в памяти, уменьшая значения sp
и высвобождая («pops») значения, увеличивая sp
.
Для sp
= $4844
со значениями 1
, 2
, 3
хранящимися в стеке ( 3
вставляется в стек как последнее значение, поэтому, находясь на вершине), память будет выглядеть так:
| 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
Примеры, как инструкции работают со стек:
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
Реферат : PUSH
будет хранить значение поверх стека, POP
будет извлекать значение из вершины стека, это очередь LIFO (последний, первый). CALL
аналогичен JP
, но также вызывает адрес следующей команды после CALL
в верхней части стека. RET
похож на JP
, выталкивая адрес из стека и прыгая на него.
Предупреждение : когда прерывания разрешены, sp
должен быть действительным во время сигнала прерывания, при этом достаточное свободное пространство зарезервировано для процедуры обработчика прерываний, так как сигнал прерывания будет хранить обратный адрес (фактический pc
) до вызова процедуры обработчика, которая может хранить дополнительные данные на стек. Любое значение перед sp
может быть изменено «неожиданно», если происходит прерывание.
Продвинутый трюк : на Z80 с PUSH
принимающим 11 тактов (11t) и POP
принимающих 10t, развернутый POP
/ PUSH
через все регистры, включая EXX
для теневых вариантов, был самым быстрым способом скопировать блок памяти, даже быстрее, чем развернутый LDI
. Но вам приходилось копировать копию между сигналами прерывания, чтобы избежать повреждения памяти. Также развернутый PUSH
был самым быстрым способом для заполнения памяти с особым значением на ZX Spectrum (опять же с риском повреждения от прерывания, если он не был установлен правильно или выполнялся под DI
).