cursos:ensamblador:avanzadas2

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:avanzadas2 [14-01-2024 07:55] – se ha restaurado la vieja versión (12-01-2024 15:11) sromerocursos:ensamblador:avanzadas2 [24-01-2024 17:25] (actual) sromero
Línea 2: Línea 2:
  
 En este capítulo vamos a ver algunas consideraciones relativas a optimizaciones y mejoras que no hemos querido incluír dentro de sus respectivos capítulos para evitar confundir al lector con código o ideas complejas en un momento en que está aprendiendo los fundamenos.. En este capítulo vamos a ver algunas consideraciones relativas a optimizaciones y mejoras que no hemos querido incluír dentro de sus respectivos capítulos para evitar confundir al lector con código o ideas complejas en un momento en que está aprendiendo los fundamenos..
 +
 +\\ 
 +===== Optimizaciones generales =====
 +
 +Veamos una serie de "optimizaciones" o construcciones de código algo más avanzadas que las que hemos visto hasta ahora para determinadas tareas:
 +
 +\\ 
 +**Copiar el flag Zero al Carry**
 +
 +<code z80>
 +    scf              ; CF = 1
 +    jr z, $+3        ; Si ZF=1, saltamos y dejamos CF=1
 +    ccf              ; Si ZF=0, al no saltar ejecutamos ccf
 +                     ; y hacemos CF=0
 +                     ; $+3 es la instrucción posterior al ccf
 +</code>
 +
 +**Copiar el flag de Carry al Zero flag**
 +
 +<code z80>
 +    ccf
 +    sbc a, a
 +</code>
 +
 +\\ 
 +**Realizar un ''NEG'' de un registro de 16 bits**
 +
 +<code z80>
 +    xor a
 +    sub Parte_baja_Registro
 +    ld Parte_baja_Registro, a
 +    sbc a, a
 +    sub Parte_alta_Registro
 +    ld Parte_alta_Registro, a
 +</code>
 +
 +Por ejemplo, para simular ''NEG HL'':
 +
 +<code z80>
 +    xor a
 +    sub l
 +    ld l, a
 +    sbc a, a
 +    sub h
 +    ld h, a
 +</code>
 +
  
 \\  \\ 
Línea 17: Línea 64:
  
 <code z80> <code z80>
-    LD DE, NNNN     ; veces a iterar+    ld de, NNNN     ; veces a iterar
  
 loop: loop:
     ; ... código de nuestro bucle ...     ; ... código de nuestro bucle ...
-    DEC DE +    dec de 
-    LD AD +    ld ad 
-    OR E +    or e 
-    JP NZ, loop+    jp nz, loop
 </code> </code>
  
-El problema es que tenemos que hacer operaciones costosas como el ''DEC DE'' (de 16 bits), perder el valor de A para poder comprobar si hemos llegado al final del bucle.+El problema es que tenemos que hacer operaciones costosas como el ''dec de'' (de 16 bits), perder el valor de A para poder comprobar si hemos llegado al final del bucle.
  
 Para eso, esta página nos propone aprovechar ''DJNZ''. Cuando usamos ''DJNZ'', el valor de B se decrementa hasta que alcanza 0. La comprobación de si el bucle ha acabado (si B == 0) se hace después del decremento, por lo que podemos aprovechar esto para hacer un bucle de 256 iteraciones si ponemos B a 0. Para eso, esta página nos propone aprovechar ''DJNZ''. Cuando usamos ''DJNZ'', el valor de B se decrementa hasta que alcanza 0. La comprobación de si el bucle ha acabado (si B == 0) se hace después del decremento, por lo que podemos aprovechar esto para hacer un bucle de 256 iteraciones si ponemos B a 0.
  
-Poniendo B a 0, tras ejecutar el código 1 vez, se decrementa B, con lo que pasa a valer $FF (255), así que nos aseguramos 255 ejecuciones más la inicial, total 256.+Poniendo B a 0, tras ejecutar el código 1 vez, se decrementa B, con lo que pasa a valer $ff (255), así que nos aseguramos 255 ejecuciones más la inicial, total 256.
  
 Debido a esto, podemos hacer algo como lo siguiente: partimos el número de 16 bits a iterar en 2 registros e iteramos el primero un total de veces almacenado en el segundo. Cada vez que el primer registro llegue a cero, volveremos a iterar 256 veces, salvo la primera vez que iteramos el "módulo" de 256. Debido a esto, podemos hacer algo como lo siguiente: partimos el número de 16 bits a iterar en 2 registros e iteramos el primero un total de veces almacenado en el segundo. Cada vez que el primer registro llegue a cero, volveremos a iterar 256 veces, salvo la primera vez que iteramos el "módulo" de 256.
Línea 38: Línea 85:
  
 <code z80> <code z80>
-    LD B, 10        ; loop LSB +    ld b, 10        ; loop LSB 
-    LD D, 3         ; loop MSB => $050A => 522 iteraciones+    ld d, 3         ; loop MSB => $050a => 522 iteraciones
  
 loop: loop:
     ; ... código de nuestro bucle ...     ; ... código de nuestro bucle ...
-    DJNZ LOOP +    djnz loop 
-    DEC D +    dec d 
-    JP NZLOOP+    jp nzloop
 </code> </code>
  
-Este bucle iterará un total de 522 veces ($050A).+Este bucle iterará un total de 522 veces ($050a).
  
 Ahora la pregunta es ¿cómo calculamos los valores que tenemos que poner en D y en B? Ahora la pregunta es ¿cómo calculamos los valores que tenemos que poner en D y en B?
Línea 55: Línea 102:
  
 <code z80> <code z80>
-    LD DE, NNNN     ; veces a iterar +    ld de, NNNN     ; veces a iterar 
-    LD BE +    ld be 
-    DEC DE +    dec de 
-    INC D           ; D y B listos para usar en nuestro bucle+    inc d           ; D y B listos para usar en nuestro bucle
 </code> </code>
  
Línea 64: Línea 111:
  
 <code z80> <code z80>
-    LD DE, NNNN     ; veces a iterar +    ld de, NNNN     ; veces a iterar 
-    LD B        ; +    ld b        ; 
-    DEC DE          ; Calculate DB value (destroys B, D and E) +    dec de          ; Calculate DB value (destroys B, D and E) 
-    INC D+    inc d
 loop: loop:
     ; ... código de nuestro bucle ...     ; ... código de nuestro bucle ...
-    DJNZ LOOP +    djnz LOOP 
-    DEC D +    dec d 
-    JP NZ, LOOP+    jp nz, LOOP
 </code> </code>
  
Línea 78: Línea 125:
  
 <code z80> <code z80>
-    LD DE, NNNN     ; veces a iterar +    ld de, NNNN     ; veces a iterar 
-    LD B        ; +    ld b        ; 
-    DEC DE          ; Calculate DB value (destroys B, D and E) +    dec de          ; Calculate DB value (destroys B, D and E) 
-    INC D +    inc d 
-    LD CD+    ld cd
  
 loop: loop:
     ; ... código de nuestro bucle ...     ; ... código de nuestro bucle ...
-    DJNZ LOOP +    djnz LOOP 
-    DEC C +    dec c 
-    JP NZ, LOOP+    jp nz, LOOP
 </code> </code>
  
Línea 95: Línea 142:
 El bucle de 16 bits estándar que hemos visto en el primer ejemplo utiliza 4 instrucciones para hacer el bucle, lo que suma un total de 28 ciclos de reloj o T-states por iteración. El bucle de 16 bits estándar que hemos visto en el primer ejemplo utiliza 4 instrucciones para hacer el bucle, lo que suma un total de 28 ciclos de reloj o T-states por iteración.
  
-En cambio, el bucle con ''DJNZ'' + ''JP'' (o ''JR'' si el código del bucle es menor de 128 bytes) utiliza ''DJNZ'', que son sólo 14 ciclos de reloj, es decir la mitad. Sólo cada 256 iteraciones se ejecutará el bucle exterior utilizando un total de 25 ciclos de reloj.+En cambio, el bucle con ''DJNZ'' + ''jp'' (o ''jr'' si el código del bucle es menor de 128 bytes) utiliza ''DJNZ'', que son sólo 14 ciclos de reloj, es decir la mitad. Sólo cada 256 iteraciones se ejecutará el bucle exterior utilizando un total de 25 ciclos de reloj.
  
 El bucle exterior se ejecuta de forma poco frecuente (1 vez cada 256 iteraciones), por lo que estamos ahorrando 14 ciclos en cada iteración y perdiendo uno cada 256. El bucle exterior se ejecuta de forma poco frecuente (1 vez cada 256 iteraciones), por lo que estamos ahorrando 14 ciclos en cada iteración y perdiendo uno cada 256.
Línea 111: Línea 158:
   * https://github.com/artyom-beilis/float16   * https://github.com/artyom-beilis/float16
  
-Finalmente, un caso muy interesante del uso de ''EX AFAF<nowiki>'</nowiki>'' es el de preservar AF en alguna operación, para poder aprovechar ese flag después.+Finalmente, un caso muy interesante del uso de ''ex afaf<nowiki>'</nowiki>'' es el de preservar AF en alguna operación, para poder aprovechar ese flag después.
  
 Por ejemplo, supongamos que hacemos un scroll de un bitmap así: Por ejemplo, supongamos que hacemos un scroll de un bitmap así:
  
 <code z80> <code z80>
-    RL (HL+    rl (hl
-    DEC L         ; este bloque RL + DEC se repite 16 veces+    dec l         ; este bloque RL + DEC se repite 16 veces
 </code> </code>
  
Línea 125: Línea 172:
  
 <code z80> <code z80>
-    RL (HL+    rl (hl
-    EX AF, AF' +    ex afaf'      ; Nos guardamos AF en AF' 
-    RL (HL+    rl (hl
-    EX AF, AF' +    ex afaf'      ; Recuperamos AF desde AF' 
-    DEC L           ; este bloque se repite 16 veces+    dec l           ; este bloque se repite 16 veces
 </code> </code>
  
  • cursos/ensamblador/avanzadas2.1705218942.txt.gz
  • Última modificación: 14-01-2024 07:55
  • por sromero