cursos:ensamblador:habituales

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:habituales [24-01-2024 17:36] – [Optimizaciones habituales] sromerocursos:ensamblador:habituales [02-02-2024 18:39] (actual) – [Comparaciones de 8 bits] sromero
Línea 5: Línea 5:
 Por ejemplo, las comparaciones de 8 y 16 bits son básicas y tendremos que usarlas decenas (sino cientos) de veces a lo largo de nuestro programa para implementar la lógica no sólo de bucles sino también de condiciones como "//¿El jugador ha colisionado con un objeto, comparando las coordenadas de ambos?//". Por ejemplo, las comparaciones de 8 y 16 bits son básicas y tendremos que usarlas decenas (sino cientos) de veces a lo largo de nuestro programa para implementar la lógica no sólo de bucles sino también de condiciones como "//¿El jugador ha colisionado con un objeto, comparando las coordenadas de ambos?//".
  
-También veremos construcciones u optimizaciones habituales en ensamblador, como utilizar ''xor a'' en lugar de ''ld a, 0'' para poner a 0 el valor del registro A. Estas "construcciones" o "trucos" se utilizan mucho en los programas en ensamblador porque ahorran memoria y además se suelen ejecutar más rápido. Se utilizan mucho hasta el punto en que son casi la "forma estándar" de realizar ese tipo de operaciones, y no es habitual ver un ''ld a, 0'' en ningún programa, ya que no tiene sentido utilizar 2 bytes y 7 ciclos de reloj para hacer algo que puedes hacer con ''XOR'' usando 1 sólo byte y 4 ciclos. Ya no es sólo una cuestión de que el programa sea más rápido, sino de que ocupe mucho menos y por tanto podamos meter más código en la limitada memoria del Spectrum.+También veremos construcciones u optimizaciones habituales en ensamblador, como utilizar ''XOR A'' en lugar de ''LD A, 0'' para poner a 0 el valor del registro A. Estas "construcciones" o "trucos" se utilizan mucho en los programas en ensamblador porque ahorran memoria y además se suelen ejecutar más rápido. Se utilizan mucho hasta el punto en que son casi la "forma estándar" de realizar ese tipo de operaciones, y no es habitual ver un ''LD A, 0'' en ningún programa, ya que no tiene sentido utilizar 2 bytes y 7 ciclos de reloj para hacer algo que puedes hacer con ''XOR'' usando 1 sólo byte y 4 ciclos. Ya no es sólo una cuestión de que el programa sea más rápido, sino de que ocupe mucho menos y por tanto podamos meter más código en la limitada memoria del Spectrum.
  
  
Línea 11: Línea 11:
 ===== Comparaciones de 8 bits ===== ===== Comparaciones de 8 bits =====
  
-Las comparaciones de valores 8 bits son situaciones extremadamente habituales en nuestros programas. En múltiples ocasiones tendremos que verificar si el valor de un determinado registro es igual, distingo, menor, mayor, menor igual o mayor igual que el valor de otro registro o que un valor inmediato.+Las comparaciones de valores de 8 bits son situaciones extremadamente habituales en nuestros programas. En múltiples ocasiones tendremos que verificar si el valor de un determinado registro es igual, distingo, menor, mayor, menor igual o mayor igual que el valor de otro registro o que un valor inmediato.
  
 Como ya vimos en el capítulo dedicado a las instrucciones básicas, las comparaciones se basan en **restas** (''SUB'' y ''SBC'') y en cómo estas afectan a los **flags** (registro F) del procesador. Las comparaciones son tan importantes, que hay una instrucción dedicada a realizar una resta descartando el resultado (evitando así alterar un registro innecesariamente), pero afectando a los flags. Esa instrucción es ''CP'' de "ComPare". Como ya vimos en el capítulo dedicado a las instrucciones básicas, las comparaciones se basan en **restas** (''SUB'' y ''SBC'') y en cómo estas afectan a los **flags** (registro F) del procesador. Las comparaciones son tan importantes, que hay una instrucción dedicada a realizar una resta descartando el resultado (evitando así alterar un registro innecesariamente), pero afectando a los flags. Esa instrucción es ''CP'' de "ComPare".
Línea 36: Línea 36:
 \\  \\ 
  
-Así, tras un ''CP n'' podemos utilizar los flas de la siguiente forma:+Así, tras un ''CP n'' podemos utilizar los flags de la siguiente forma:
  
 \\  \\ 
-   * **A == N** (A igual n): Si se activa **ZF** (flag de Zero), es porque el resultado de la resta es 0, es decir, A < n son iguales.+   * **A == N** (A igual n): Si se activa **ZF** (flag de Zero), es porque el resultado de la resta es 0, es decir, A y N son iguales.
  
    * **A != n** (A distinto de n): Si no se activa **ZF** (flag de Zero), es porque el resultado de la resta no es 0, es decir A y n son diferentes.    * **A != n** (A distinto de n): Si no se activa **ZF** (flag de Zero), es porque el resultado de la resta no es 0, es decir A y n son diferentes.
  
-   * **A < n** (A menor que n): Si no era igual, y se activa **CF** (flag de Carry), es porque el resultado de la resta es negativo, es decir, A es menor que B.+   * **A < n** (A menor que n): Si no era igual, y se activa **CF** (flag de Carry), es porque el resultado de la resta es negativo, es decir, A es menor que B. No es necesario comprobar primero el valor del ZF, si CF está activo, entonces A es menor que N, siempre.
  
    * **A > n** (mayor que): Si no era igual, y no se activa **CF** (flag de Carry), es porque el resultado de la resta es positivo, es decir, A es mayor que B.    * **A > n** (mayor que): Si no era igual, y no se activa **CF** (flag de Carry), es porque el resultado de la resta es positivo, es decir, A es mayor que B.
Línea 50: Línea 50:
 \\  \\ 
  
-La igualdad requiere sólo verificar el flag de Zero, mientras que el resto de comparaciones requiere utilizar también el flag de Carry:+La igualdad requiere sólo verificar el flag de Zero, la comparación "menor que" requiere sólo verificar el flag de Carry, y el resto de comparaciones requiere verificar el estado de ambos:
  
 <code> <code>
Línea 57: Línea 57:
 =       =>     Z=1 =       =>     Z=1
 !=      =>     Z=0 !=      =>     Z=0
-<       =>     Z=0, C=1+<       =>     C=1
 >       =>     Z=0, C=0 >       =>     Z=0, C=0
 <=      =>     Z=1, C=1 <=      =>     Z=1, C=1
Línea 74: Línea 74:
 </code> </code>
  
-Veamos ejemplos de código, comparando A con 50 (podemos usar para los saltos tanto ''jp'' como ''jr''):+Veamos ejemplos de código, comparando A con 50 (podemos usar para los saltos tanto ''JP'' como ''JR''):
  
-Para comparar si **A == 50**, simplemente comprobamos ZF:+Para comparar si **A == 50** o si **A != 50**, simplemente comprobamos ZF:
  
 <code z80> <code z80>
Línea 89: Línea 89:
     ; igual a 50     ; igual a 50
     ; (... codigo para caso a == 50 ...)     ; (... codigo para caso a == 50 ...)
- 
-fin_comparacion: 
-</code> 
- 
-Para comparar si **A != 50**, de nuevo comprobamos ZF: 
- 
-<code z80> 
-    cp 50 
-    jr z, distinto_de_50 
- 
-    ; igual a 50 
-    ; (... codigo para caso a == 50 ...) 
-    jr fin_comparacion 
- 
-distinto_a_50: 
-    ; (... codigo para caso a != 50 ...) 
  
 fin_comparacion: fin_comparacion:
Línea 144: Línea 128:
 <code z80> <code z80>
     cp 50     cp 50
-    jp ncmenor_o_igual_que_50 +    jp cmenor_que_50 
-    jp nz, menor_o_igual_que_50     ; => Si no salto, es que C = 1+    jp nz, mayor_que_50             ; => Si no salto, es que C = 0
                                     ;    Ahora o es '=' o es '<' segun Z                                     ;    Ahora o es '=' o es '<' segun Z
  
-    ; mayor o igual que 50+    ; igual que 50 
 +    ; (... codigo para caso a == 50 ...) 
 +     
 +    jr fin_comparacion 
 + 
 +mayor_que_50:
     ; (... codigo para caso a > 50 ...)     ; (... codigo para caso a > 50 ...)
     jr fin_comparacion     jr fin_comparacion
  
-menor_o_igual_que_50+menor_que_50
-    ; (... codigo para caso a <50 ...)+    ; (... codigo para caso a < 50 ...)
  
 fin_comparacion: fin_comparacion:
 </code> </code>
  
- Como se puede ver en el código, tenemos que añadir un ''jp nz'' o ''jp z'' tras el chequeo del carry para comprobar si es "menor o igual". Si queremos ahorrar varios t-estados, podemos hacer las comparaciones de ''>='' y ''<='' sin igualdad, pero utilizando el número anterior o el siguiente. Repitamos el ejemplo anterior, pero con 51 (''>='') o con 49 (''<=''):+ Como se puede ver en el código, tenemos que añadir un ''JP NZ'' o ''JP Z'' tras el chequeo del carry para comprobar si es "menor o igual". Si queremos ahorrar varios t-estados, podemos hacer las comparaciones de ''>='' y ''<='' sin igualdad, pero utilizando el número anterior o el siguiente. Repitamos el ejemplo anterior, pero con 51 (''>='') o con 49 (''<=''):
  
 <code z80> <code z80>
Línea 165: Línea 154:
     ; saltaría con >=51 es decir, con >50     ; saltaría con >=51 es decir, con >50
     cp 50+1     cp 50+1
-    jp nc, mayor_O_IGUAL_que_51      ; = mayor_que_50+    jp nc, mayor_que_50           ; => mayor O IGUAL que 51 = mayor que 50
  
-    ; aqui A < 50+    ; aqui A <50
     jr fin_comparacion     jr fin_comparacion
  
 mayor_que_50: mayor_que_50:
-    aqui A >= 51 y por tanto A > 50+    aqui A >= 51 y por tanto A > 50
  
 fin_comparacion: fin_comparacion:
Línea 178: Línea 167:
 <code z80> <code z80>
     ; comparamos con valor -1 y entonces sí que podemos hacer JP C     ; comparamos con valor -1 y entonces sí que podemos hacer JP C
-    ; y comprobar "mayor_que_50" mediante "mayor_o_igual_que_49".+    ; y comprobar "menor_que_50" mediante "mayor_o_igual_que_49".
     ; saltaría con <=49 es decir, con <50     ; saltaría con <=49 es decir, con <50
     cp 50-1     cp 50-1
     jp c, menor_igual_que_49        ; = menor_que_50     jp c, menor_igual_que_49        ; = menor_que_50
  
-    ; aqui A >50+    ; aqui A > 50
     jr fin_comparacion     jr fin_comparacion
  
-mayor_o_igual_que_49:+menor_igual_que_49:
     ; aqui A <= 49 y por tanto A < 50     ; aqui A <= 49 y por tanto A < 50
  
 fin_comparacion: fin_comparacion:
 </code> </code>
- 
  
 Recordamos que ''CP'', y en general el uso de los flags (con ''DEC'', ''INC'', ''AND/OR/XOR'', etc) no nos limita a usar después ''JP'' o ''JR'', sino que también podemos usarlo para salir de las rutinas con ''RET'' o hacer llamadas condicionales con ''CALL''; Recordamos que ''CP'', y en general el uso de los flags (con ''DEC'', ''INC'', ''AND/OR/XOR'', etc) no nos limita a usar después ''JP'' o ''JR'', sino que también podemos usarlo para salir de las rutinas con ''RET'' o hacer llamadas condicionales con ''CALL'';
Línea 306: Línea 294:
    * Si **HL > DE** => Z=0 y C=0.    * Si **HL > DE** => Z=0 y C=0.
  
-De la misma forma, podemos realizar rutinas específicas para compara condiciones como por ejemplo, "mayor o igual" (**>=**):+De la misma forma, podemos realizar rutinas específicas para comparar condiciones como por ejemplo, "mayor o igual" (**>=**):
  
 <code z80> <code z80>
Línea 368: Línea 356:
 \\  \\ 
 **Resetear el Carry Flag** **Resetear el Carry Flag**
 +
 +No existe una instrucción para poner el Carry Flag a 0, aunque sí una para ponerlo a 1, y una para complementarlo. Esto permite ponerlo a 0 usando 2 instrucciones (2 bytes) y 8 t-estados. Sin embargo, es más fácil hacerlo usando cualquier operación lógica que lo resetee, como ''or'':
  
 <code z80> <code z80>
Línea 493: Línea 483:
  
     ; Óptimo:     ; Óptimo:
 +    rrca
     rrca     rrca
     rrca     rrca
Línea 591: Línea 582:
     ; Con bit 0:     ; Con bit 0:
     rra                 ; 1 byte, 4 t-estados     rra                 ; 1 byte, 4 t-estados
-    jr z, destino+    jr c, destino
  
     ; Con bit 7:     ; Con bit 7:
-    rla                 ; byte, 4 t-estados +    rla                 ; byte, 4 t-estados 
-    call z, destino+    call c, destino
 </code> </code>
  
  • cursos/ensamblador/habituales.1706117795.txt.gz
  • Última modificación: 24-01-2024 17:36
  • por sromero