Assembly Language
La pila
Buscar..
Observaciones
La pila de computadoras es como una pila de libros. PUSH agrega uno a la parte superior y POP quita lo máximo. Al igual que en la vida real, la pila no puede ser infinita, por lo que tiene el tamaño máximo. La pila se puede usar para ordenar algoritmos, para manejar una mayor cantidad de datos o para valores seguros de registros mientras se realiza otra operación.
Zilog Z80 Stack
El registro sp
se utiliza como puntero de pila , apuntando al último valor almacenado en pila ("parte superior" de pila). Entonces EX (sp),hl
intercambiará el valor de hl
con el valor en la parte superior de la pila.
Contrariamente a la palabra "top", la pila crece en la memoria al disminuir los valores de sp
, y libera ("pops") al aumentar sp
.
Para sp
= $4844
con los valores 1
, 2
, 3
almacenados en la pila (los 3
se colocan en la pila como último valor, por lo que están en la parte superior de la misma), la memoria se verá así:
| 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
Ejemplos, cómo funcionan las instrucciones con la pila:
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
Resumen : PUSH
almacenará el valor en la parte superior de la pila, POP
obtendrá el valor de la parte superior de la pila, es una cola LIFO (último en entrar, primero en salir). CALL
es igual que JP
, pero también empuja la dirección de la siguiente instrucción después de CALL
en la parte superior de la pila. RET
es similar a JP
también, sacando la dirección de la pila y saltando a ella.
Advertencia : cuando las interrupciones están habilitadas, el sp
debe ser válido durante la señal de interrupción, con suficiente espacio libre reservado para la rutina del manejador de interrupciones, ya que la señal de interrupción almacenará la dirección de retorno ( pc
real) antes de llamar a la rutina del manejador, que puede almacenar más datos en apilar también. Cualquier valor por delante de sp
puede ser modificado así "inesperadamente", si ocurre una interrupción.
Truco avanzado : en Z80 con PUSH
tomó 11 ciclos de reloj (11t) y POP
tomó 10t, el POP
/ PUSH
desenrollado a través de todos los registros, incluyendo EXX
para las variantes de sombra, fue la forma más rápida de copiar bloques de memoria, incluso más rápido que el LDI
desenrollado. Pero tuvo que programar la copia entre las señales de interrupción para evitar la corrupción de la memoria. También el PUSH
enrollado fue la forma más rápida de llenar la memoria con un valor particular en el ZX Spectrum (nuevamente, con el riesgo de corrupción por Interrupción, si no se cronometra correctamente, o se realiza bajo DI
).