cursos:ensamblador:lenguaje_4

Diferencias

Muestra las diferencias entre dos versiones de la página.

Enlace a la vista de comparación

Ambos lados, revisión anterior Revisión previa
Próxima revisión
Revisión previa
cursos:ensamblador:lenguaje_4 [19-01-2024 07:21] sromerocursos:ensamblador:lenguaje_4 [22-01-2024 07:54] (actual) – [PUSH y POP] sromero
Línea 156: Línea 156:
     xx   = (SP)     xx   = (SP)
     SP   = SP+2     SP   = SP+2
 +</code>
 +
 + Visto en "pseucódigo BASIC", ambos comandos serían:
 +
 +<code z80>
 +push hl  =   LET SP = SP-2
 +             POKE (SP+1), H
 +             POKE SP, L
 +
 +pop hl     LET L = PEEK SP
 +             LET H = PEEK (SP+1)
 +             LET SP = SP+2
 </code> </code>
  
Línea 427: Línea 439:
  Esto es lo que se conoce como "contented memory" o "memoria en contienda".  Esto es lo que se conoce como "contented memory" o "memoria en contienda".
  
- 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 ''PUSH'' y ''POP'' es, físicamente, un acceso de escritura y lectura a memoria, y las rutinas de nuestro programa harán, seguro, gran uso de ellas, además de los ''CALL''s y ''RET''s (''PUSH PC'' + ''jp DIR'' / ''POP PC'').+ 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 ''PUSH'' y ''POP'' es, físicamente, un acceso de escritura y lectura a memoria, y las rutinas de nuestro programa harán, seguro, gran uso de ellas, además de los ''CALL''s y ''RET''s (''PUSH PC'' + ''JP DIR'' / ''POP PC'').
  
  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 449: Línea 461:
  Para saltar a subrutinas utilizamos la instrucción ''CALL'', y estas deben de terminar en un ''RET''.  Para saltar a subrutinas utilizamos la instrucción ''CALL'', y estas deben de terminar en un ''RET''.
  
- El lector podría preguntar, ¿por qué no utilizar las instrucciones de salto ''jp'' y ''jr'' vistas hasta ahora? La respuesta es: debido a la necesidad de una dirección de retorno.+ El lector podría preguntar, ¿por qué no utilizar las instrucciones de salto ''JP'' y ''JR'' vistas hasta ahora? La respuesta es: debido a la necesidad de una dirección de retorno.
  
- Veamos un ejemplo ilustrativo de la importancia de call/ret realizando una subrutina que se utilice ''jp'' para su llamada. Supongamos la siguiente "subrutina" sin ''RET'':+ Veamos un ejemplo ilustrativo de la importancia de call/ret realizando una subrutina que se utilice ''JP'' para su llamada. Supongamos la siguiente "subrutina" sin ''RET'':
  
 <code z80> <code z80>
Línea 467: Línea 479:
  Nuestra función/subrutina de ejemplo espera obtener en A un valor, y devuelve el resultado de su ejecución en B. Antes de llamar a esta rutina, nosotros deberemos poner en A el valor sobre el que actuar, y posteriormente interpretar el resultado (sabiendo que lo tenemos en B).  Nuestra función/subrutina de ejemplo espera obtener en A un valor, y devuelve el resultado de su ejecución en B. Antes de llamar a esta rutina, nosotros deberemos poner en A el valor sobre el que actuar, y posteriormente interpretar el resultado (sabiendo que lo tenemos en B).
  
- Pero, ¿cómo llamamos a las subrutinas y volvemos de ellas? Comencemos probando con ''jp'':+ Pero, ¿cómo llamamos a las subrutinas y volvemos de ellas? Comencemos probando con ''JP'':
  
 <code z80> <code z80>
Línea 648: Línea 660:
 </code> </code>
  
- Del mismo modo, el uso de ''CALL'' condicionado al estado de flags (''call Z'', ''call NZ'', ''call M'', ''call P'', etc) nos permitirá llamar o no a funciones según el estado de un flag.+ Del mismo modo, el uso de ''CALL'' condicionado al estado de flags (''CALL Z'', ''CALL NZ'', ''CALL M'', ''CALL P'', etc) nos permitirá llamar o no a funciones según el estado de un flag.
  
  Al igual que ''CALL'' y ''RET'', sus versiones condicionales no afectan al estado de los flags.  Al igual que ''CALL'' y ''RET'', sus versiones condicionales no afectan al estado de los flags.
Línea 677: Línea 689:
 <code z80> <code z80>
 ;-------------------------------------------------------------- ;--------------------------------------------------------------
-MULTIPLI: Multiplica DE*BC +Mult_HL_DE: Multiplica DE*BC 
-      Entrada:        DE: Multiplicando, +; 
-                      BC: Multiplicador +Entrada:        DE: Multiplicando, 
-      Salida:         HL: Resultado. +                BC: Multiplicador 
-      Modifica:       Ningun registro aparte de HL+; Salida:         HL: Resultado. 
 +; Modifica:       Ningun registro aparte de HL
 ;-------------------------------------------------------------- ;--------------------------------------------------------------
-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 700: Línea 713:
 </code> </code>
  
- Antes de hacer la llamada a MULTIPLICA, tendremos que cargar en DE y en BC los valores que queremos multiplicar, de modo que si estos valores están en otros registros o en memoria, tendremos que moverlos a DE y BC.+ Antes de hacer la llamada a ''Mult_HL_DE'', tendremos que cargar en DE y en BC los valores que queremos multiplicar, de modo que si estos valores están en otros registros o en memoria, tendremos que moverlos a DE y BC.
  
  Además, sabemos que la salida nos será devuelta en HL, con lo que si dicho registro contenía algún valor importante y que no debemos perder en el código que llama a la rutina, deberemos preservarlo previamente.  Además, sabemos que la salida nos será devuelta en HL, con lo que si dicho registro contenía algún valor importante y que no debemos perder en el código que llama a la rutina, deberemos preservarlo previamente.
Línea 758: Línea 771:
     ld bc, (size)      ; Leemos los parametros     ld bc, (size)      ; Leemos los parametros
  
-    (Codigo)+    (... código ...)
  
     ld (salida), a     ; Devolvemos un valor     ld (salida), a     ; Devolvemos un valor
Línea 783: 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, usando el valor de SP para acceder a ellos. En ensamblador no es normal utilizar este método a menos que tengamos muchos parámetros, no nos quepan en registros y que queramos ir rescatándolos de la pila en el punto de la función que nos interese (sea con el valor de SP o con POP).  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, usando el valor de SP para acceder a ellos. En ensamblador no es normal utilizar este método a menos que tengamos muchos parámetros, no nos quepan en registros y que queramos ir rescatándolos de la pila en el punto de la función que nos interese (sea con el valor de SP o con POP).
  
-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 ''PUSH'' y dentro de la rutina los vamos recogiendo con ''POP'':
  
  Veamos unos ejemplos:  Veamos unos ejemplos:
Línea 881: Línea 894:
 <code z80> <code z80>
 BuclePrincipal: BuclePrincipal:
-    call Leer_Teclado +    call LeerTeclado             ; o Leer_Teclado 
-    call Logica_Juego +    call LogicaJuego             ; o Logica_Juego 
-    call Comprobar_Estado +    call ComprobarEstado         ; o Comprobar_Estado 
-    jp Bucle_Principal+    jp BuclePrincipal            ; o Bucle_Principal
  
-Leer_Teclado:+LeerTeclado:
     ret     ret
  
-Logica_Juego:+LogicaJuego:
     ret     ret
  
-Comprobar_Estado:+ComprobarEstado:
     ret     ret
 </code> </code>
  • cursos/ensamblador/lenguaje_4.1705648861.txt.gz
  • Última modificación: 19-01-2024 07:21
  • por sromero