Diferencias
Muestra las diferencias entre dos versiones de la página.
Ambos lados, revisión anterior Revisión previa Próxima revisión | Revisión previa | ||
cursos:ensamblador:lenguaje_4 [19-01-2024 07:14] – sromero | cursos:ensamblador:lenguaje_4 [22-01-2024 07:54] (actual) – [PUSH y POP] sromero | ||
---|---|---|---|
Línea 62: | Línea 62: | ||
</ | </ | ||
+ | (Nota: como veremos más adelante, para poner la pila al final de la memoria en realidad hay que ponerla en $0000, pero por motivos didácticos y para simplificar la explicación, | ||
+ | |||
Si ahora hacemos: | Si ahora hacemos: | ||
Línea 141: | Línea 143: | ||
Así pues, podemos hacer **PUSH** y **POP** de los siguientes registros: | Así pues, podemos hacer **PUSH** y **POP** de los siguientes registros: | ||
- | * PUSH: AF, BC, DE, HL, IX, IY | + | * '' |
- | * POP : AF, BC, DE, HL, IX, IY | + | * '' |
Lo que hacen PUSH y POP, tal y como funciona la pila, es: | Lo que hacen PUSH y POP, tal y como funciona la pila, es: | ||
< | < | ||
- | PUSH xx : | + | push xx : |
| | ||
(SP) = xx | (SP) = xx | ||
- | POP xx : | + | pop xx : |
xx = (SP) | xx = (SP) | ||
SP = SP+2 | SP = SP+2 | ||
+ | </ | ||
+ | |||
+ | Visto en " | ||
+ | |||
+ | <code z80> | ||
+ | push hl = LET SP = SP-2 | ||
+ | POKE (SP+1), H | ||
+ | POKE SP, L | ||
+ | |||
+ | pop hl | ||
+ | LET H = PEEK (SP+1) | ||
+ | LET SP = SP+2 | ||
</ | </ | ||
Línea 162: | Línea 176: | ||
| | ||
| | ||
- | POP xx |- - - - - -| | + | pop xx |- - - - - -| |
- | PUSH xx |- - - - - -| | + | push xx |- - - - - -| |
</ | </ | ||
Línea 178: | Línea 192: | ||
<code z80> | <code z80> | ||
- | push bc | + | push bc ; Guardamos el valor de BC |
- | (código) | + | (código) |
- | pop bc ; Recuperamos el valor que teníamos en BC | + | pop bc |
</ | </ | ||
Línea 192: | Línea 206: | ||
bucle: | bucle: | ||
- | push bc | + | push bc ; Guardamos BC |
ld b, 1 | ld b, 1 | ||
add a, b | add a, b | ||
- | pop bc ; Recuperamos BC | + | pop bc |
djnz bucle | djnz bucle | ||
</ | </ | ||
Línea 212: | Línea 226: | ||
<code z80> | <code z80> | ||
- | ld b, 20 ; repetimos bucle externo 20 veces | + | ld b, 20 |
bucle_externo: | bucle_externo: | ||
- | push bc | + | push bc ; Nos guardamos el valor de BC |
- | ld b, 100 | + | ld b, 100 ; Iteraciones del bucle interno |
bucle_interno: | bucle_interno: | ||
(... código ...) | (... código ...) | ||
- | djnz bucle_interno | + | djnz bucle_interno |
- | pop bc ; Recuperamos el valor de B | + | pop bc |
- | djnz bucle_externo | + | djnz bucle_externo |
</ | </ | ||
Línea 229: | Línea 243: | ||
<code z80> | <code z80> | ||
- | ld b, 20 ; repetimos bucle externo 20 veces | + | ld b, 20 |
bucle_externo: | bucle_externo: | ||
- | ld d, b | + | ld d, b ; Nos guardamos el valor de B |
- | ld b, 100 | + | ld b, 100 ; Iteraciones del bucle interno |
bucle_interno: | bucle_interno: | ||
- | (... código ...) ; En este codigo no podemos usar D | + | (... código ...) |
- | djnz bucle_interno | + | djnz bucle_interno |
- | ld b, d | + | ld b, d ; Recuperamos el valor de B |
- | djnz bucle_externo | + | djnz bucle_externo |
</ | </ | ||
Línea 247: | Línea 261: | ||
\\ | \\ | ||
- | * Como veremos en el próximo apartado, la pila es la clave de las subrutinas ('' | + | * Como veremos en el próximo apartado, la pila es la clave de las subrutinas ('' |
\\ | \\ | ||
Línea 269: | Línea 283: | ||
; Simulando "EX DE, BC" | ; Simulando "EX DE, BC" | ||
| | ||
- | push bc | + | push bc ; Apilamos BC |
- | push de | + | push de ; Apilamos DE |
- | pop bc ; Desapilamos BC | + | pop bc |
- | ; ahora BC=(valor apilado en push de) | + | |
- | pop de ; Desapilamos DE | + | pop de |
- | ; ahora DE=(valor apilado en push bc) | + | |
</ | </ | ||
Línea 280: | Línea 294: | ||
<code z80> | <code z80> | ||
- | ; Simulando "EX DE, BC" | + | ; Simulando "ex de, bc" |
push hl | push hl | ||
ld l, c | ld l, c | ||
Línea 292: | Línea 306: | ||
ex (sp), hl | ex (sp), hl | ||
ex (sp), ix | ex (sp), ix | ||
- | EX (SP), IY | + | ex (sp), iy |
</ | </ | ||
Línea 309: | Línea 323: | ||
|< 50% 50% 50% >| | |< 50% 50% 50% >| | ||
^ Instrucción incorrecta ^ Alternativa ^ | ^ Instrucción incorrecta ^ Alternativa ^ | ||
- | | EX BC, HL | push bc\\ ex (sp), hl\\ pop bc | | + | | ex bc, hl | push bc\\ ex (sp), hl\\ pop bc | |
- | | EX BC, IX | push bc\\ ex (sp), ix\\ pop bc | | + | | ex bc, ix | push bc\\ ex (sp), ix\\ pop bc | |
- | | EX BC, IY | push bc\\ EX (SP), IY\\ pop bc | | + | | ex bc, iy | push bc\\ ex (sp), iy\\ pop bc | |
- | | EX AF, HL | push af\\ ex (sp), hl\\ pop af | | + | | ex af, hl | push af\\ ex (sp), hl\\ pop af | |
- | | EX AF, IX | push af\\ ex (sp), ix\\ pop af | | + | | ex af, ix | push af\\ ex (sp), ix\\ pop af | |
- | | EX AF, IY | push af\\ EX (SP), IY\\ pop af | | + | | ex af, iy | push af\\ ex (sp), iy\\ pop af | |
| ex de, ix | push de\\ ex (sp), ix\\ pop de | | | ex de, ix | push de\\ ex (sp), ix\\ pop de | | ||
- | | EX DE, IY | push de\\ EX (SP), IY\\ pop de | | + | | ex de, iy | push de\\ ex (sp), iy\\ pop de | |
\\ | \\ | ||
Línea 425: | Línea 439: | ||
Esto es lo que se conoce como " | Esto es lo que se conoce como " | ||
- | Esto implica que las lecturas y escrituras de nuestro programa (ejecutado por el Z80) en la página de memoria de 16KB que va desde 16384 a 32767 se ven interrumpidas de forma constante por la ULA (aunque de forma transparente para nuestro programa), por lo que ubicar la pila en esta zona puede suponer una ralentización con respecto a ubicarla más arriba de la dirección 32768. Recuerda que cada operación '' | + | Esto implica que las lecturas y escrituras de nuestro programa (ejecutado por el Z80) en la página de memoria de 16KB que va desde 16384 a 32767 se ven interrumpidas de forma constante por la ULA (aunque de forma transparente para nuestro programa), por lo que ubicar la pila en esta zona puede suponer una ralentización con respecto a ubicarla más arriba de la dirección 32768. Recuerda que cada operación '' |
Por lo tanto, si establecemos la pila por debajo de nuestro programa, y tenemos nuestro programa en 32768, tendremos la pila en contended memory, lo cual implica que funcionará un poco más lenta en general que tener la pila por encima. | Por lo tanto, si establecemos la pila por debajo de nuestro programa, y tenemos nuestro programa en 32768, tendremos la pila en contended memory, lo cual implica que funcionará un poco más lenta en general que tener la pila por encima. | ||
Línea 445: | Línea 459: | ||
Las subrutinas son bloques de código máquina a las cuales saltamos, hacen su tarea asignada, y devuelven el control al punto en que fueron llamadas. A veces, esperan recibir los registros con una serie de valores y devuelven registros con los valores resultantes. | Las subrutinas son bloques de código máquina a las cuales saltamos, hacen su tarea asignada, y devuelven el control al punto en que fueron llamadas. A veces, esperan recibir los registros con una serie de valores y devuelven registros con los valores resultantes. | ||
- | Para saltar a subrutinas utilizamos la instrucción '' | + | Para saltar a subrutinas utilizamos la instrucción '' |
- | El lector podría preguntar, ¿por qué no utilizar las instrucciones de salto '' | + | El lector podría preguntar, ¿por qué no utilizar las instrucciones de salto '' |
- | | + | |
<code z80> | <code z80> | ||
Línea 465: | Línea 479: | ||
| | ||
- | Pero, ¿cómo llamamos a las subrutinas y volvemos de ellas? Comencemos probando con '' | + | Pero, ¿cómo llamamos a las subrutinas y volvemos de ellas? Comencemos probando con '' |
<code z80> | <code z80> | ||
Línea 508: | Línea 522: | ||
===== Uso de CALL y RET ===== | ===== Uso de CALL y RET ===== | ||
- | '' | + | '' |
¿Y para qué sirve eso? Para que lo aprovechemos dentro de nuestra subrutina con '' | ¿Y para qué sirve eso? Para que lo aprovechemos dentro de nuestra subrutina con '' | ||
Línea 523: | Línea 537: | ||
</ | </ | ||
- | | + | |
<code z80> | <code z80> | ||
Línea 542: | Línea 556: | ||
</ | </ | ||
- | En esta ocasión, cuando ejecutamos el primer '' | + | En esta ocasión, cuando ejecutamos el primer '' |
- | Al acabar la subrutina encontramos el '' | + | Al acabar la subrutina encontramos el '' |
- | Al hablar de la pila os contamos lo importante que era mantener la misma cantidad de PUSH que de POPs en nuestro código. Ahora entenderéis por qué: si dentro de una subrutina hacéis un '' | + | Al hablar de la pila os contamos lo importante que era mantener la misma cantidad de PUSH que de POPs en nuestro código. Ahora entenderéis por qué: si dentro de una subrutina hacéis un '' |
<code z80> | <code z80> | ||
Línea 561: | Línea 575: | ||
</ | </ | ||
- | Aquí '' | + | Aquí '' |
- | Ni '' | + | Ni '' |
< | < | ||
Línea 578: | Línea 592: | ||
La instrucción **RST** es un resquicio de la compatibilidad que el Z80 tiene con el procesador 8080. | La instrucción **RST** es un resquicio de la compatibilidad que el Z80 tiene con el procesador 8080. | ||
- | '' | + | '' |
Las siguientes instrucciones son equivalentes en cuanto a resultado de la ejecución: | Las siguientes instrucciones son equivalentes en cuanto a resultado de la ejecución: | ||
Línea 646: | Línea 660: | ||
</ | </ | ||
- | Del mismo modo, el uso de '' | + | Del mismo modo, el uso de '' |
- | Al igual que '' | + | Al igual que '' |
< | < | ||
Línea 667: | Línea 681: | ||
==== Método 1: Uso de registros ==== | ==== Método 1: Uso de registros ==== | ||
- | Este método consiste en modificar unos registros concretos antes de hacer el '' | + | Este método consiste en modificar unos registros concretos antes de hacer el '' |
Este método es el más habitual en los programas en ensamblador siempre y cuando no tengamos más parámetros de entrada a la rutina que registros existentes en el Z80. | Este método es el más habitual en los programas en ensamblador siempre y cuando no tengamos más parámetros de entrada a la rutina que registros existentes en el Z80. | ||
Línea 675: | Línea 689: | ||
<code z80> | <code z80> | ||
; | ; | ||
- | ; MULTIPLI: Multiplica DE*BC | + | ; Mult_HL_DE: Multiplica DE*BC |
- | ; | + | ; |
- | ; | + | ; Entrada: |
- | ; | + | ; |
- | ; | + | ; Salida: |
+ | ; Modifica: | ||
; | ; | ||
- | MULTIPLICA: | + | Mult_HL_DE: |
push af ; Preservamos AF porque F se va a modificar | push af ; Preservamos AF porque F se va a modificar | ||
push bc ; Preservamos BC porque su valor se pierde | push bc ; Preservamos BC porque su valor se pierde | ||
ld hl, 0 | ld hl, 0 | ||
- | MULTI01: | + | multiloop_01: |
add hl, de | add hl, de | ||
dec bc | dec bc | ||
ld a, b | ld a, b | ||
or c | or c | ||
- | jr nz, MULTI01 | + | jr nz, multiloop_01 |
pop bc ; Rescatamos el valor de BC | pop bc ; Rescatamos el valor de BC | ||
Línea 698: | Línea 713: | ||
</ | </ | ||
- | Antes de hacer la llamada a MULTIPLICA, tendremos que cargar en DE y en BC los valores que queremos multiplicar, | + | Antes de hacer la llamada a '' |
| | ||
Línea 756: | Línea 771: | ||
ld bc, (size) | ld bc, (size) | ||
- | (Codigo) | + | (... código ...) |
ld (salida), a ; Devolvemos un valor | ld (salida), a ; Devolvemos un valor | ||
Línea 781: | Línea 796: | ||
En C (y en otros lenguajes de programación) los parámetros se insertan en la pila en el orden en que son leídos. La subrutina después lee los valores sin desapilarlos, | En C (y en otros lenguajes de programación) los parámetros se insertan en la pila en el orden en que son leídos. La subrutina después lee los valores sin desapilarlos, | ||
- | En ese caso, simplemente apilamos los parámetros con PUSH y dentro de la rutina los vamos recogiendo con POP: | + | En ese caso, simplemente apilamos los parámetros con '' |
| | ||
Línea 810: | Línea 825: | ||
| | ||
- | También podemos usar acceso directo a memoria mediante el valor de SP saltándonos los 2 bytes de la dirección de retorno introducida en la pila por el '' | + | También podemos usar acceso directo a memoria mediante el valor de SP saltándonos los 2 bytes de la dirección de retorno introducida en la pila por el '' |
<code z80> | <code z80> | ||
Línea 879: | Línea 894: | ||
<code z80> | <code z80> | ||
BuclePrincipal: | BuclePrincipal: | ||
- | call Leer_Teclado | + | call LeerTeclado |
- | call Logica_Juego | + | call LogicaJuego |
- | call Comprobar_Estado | + | call ComprobarEstado |
- | jp Bucle_Principal | + | jp BuclePrincipal |
- | Leer_Teclado: | + | LeerTeclado: |
ret | ret | ||
- | Logica_Juego: | + | LogicaJuego: |
ret | ret | ||
- | Comprobar_Estado: | + | ComprobarEstado: |
ret | ret | ||
</ | </ |