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:avanzadas2 [08-01-2024 09:23] – sromero | cursos: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 " | ||
+ | |||
+ | \\ | ||
+ | **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 | ||
+ | </ | ||
+ | |||
+ | **Copiar el flag de Carry al Zero flag** | ||
+ | |||
+ | <code z80> | ||
+ | ccf | ||
+ | sbc a, a | ||
+ | </ | ||
+ | |||
+ | \\ | ||
+ | **Realizar un '' | ||
+ | |||
+ | <code z80> | ||
+ | xor a | ||
+ | sub Parte_baja_Registro | ||
+ | ld Parte_baja_Registro, | ||
+ | sbc a, a | ||
+ | sub Parte_alta_Registro | ||
+ | ld Parte_alta_Registro, | ||
+ | </ | ||
+ | |||
+ | Por ejemplo, para simular '' | ||
+ | |||
+ | <code z80> | ||
+ | xor a | ||
+ | sub l | ||
+ | ld l, a | ||
+ | sbc a, a | ||
+ | sub h | ||
+ | ld h, a | ||
+ | </ | ||
+ | |||
\\ | \\ | ||
Línea 17: | Línea 64: | ||
<code z80> | <code z80> | ||
- | | + | |
loop: | loop: | ||
; ... código de nuestro bucle ... | ; ... código de nuestro bucle ... | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
</ | </ | ||
- | El problema es que tenemos que hacer operaciones costosas como el "**DEC DE**" | + | El problema es que tenemos que hacer operaciones costosas como el '' |
- | 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 |
- | 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 " | 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 " | ||
Línea 38: | Línea 85: | ||
<code z80> | <code z80> | ||
- | | + | |
- | | + | |
loop: | loop: | ||
; ... código de nuestro bucle ... | ; ... código de nuestro bucle ... | ||
- | | + | |
- | | + | |
- | | + | |
</ | </ | ||
- | 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> | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
</ | </ | ||
Línea 64: | Línea 111: | ||
<code z80> | <code z80> | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
loop: | loop: | ||
; ... código de nuestro bucle ... | ; ... código de nuestro bucle ... | ||
- | | + | |
- | | + | |
- | | + | |
</ | </ | ||
Línea 78: | Línea 125: | ||
<code z80> | <code z80> | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
loop: | loop: | ||
; ... código de nuestro bucle ... | ; ... código de nuestro bucle ... | ||
- | | + | |
- | | + | |
- | | + | |
</ | </ | ||
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 '' |
El bucle exterior se ejecuta de forma poco frecuente (1 vez cada 256 iteraciones), | El bucle exterior se ejecuta de forma poco frecuente (1 vez cada 256 iteraciones), | ||
Línea 105: | Línea 152: | ||
===== Uso de los Shadow Registers ===== | ===== Uso de los Shadow Registers ===== | ||
- | Cuando explicamos los //Shadow Registers//, | + | Cuando explicamos los //Shadow Registers//, |
Un ejemplo de uso de los registros alternativos es multiplicar vectores 16 bits por escalares, aritmética de punto flotante, como se puede ver en la siguiente URL: | Un ejemplo de uso de los registros alternativos es multiplicar vectores 16 bits por escalares, aritmética de punto flotante, como se puede ver en la siguiente URL: | ||
Línea 111: | Línea 158: | ||
* https:// | * https:// | ||
- | Finalmente, un caso muy interesante del uso de **EX AF, AF'** es el de preservar AF en alguna operación, para poder aprovechar ese flag después. | + | Finalmente, un caso muy interesante del uso de '' |
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> | ||
- | | + | |
- | | + | |
</ | </ | ||
Línea 124: | Línea 171: | ||
¿Qué ocurre si queremos scrollear 2 pixeles, y necesitamos no perder el Carry Flag del primer RL cuando hacemos el segundo? Pues que podemos preservarlo dejándolo en AF' y recuperándolo después: | ¿Qué ocurre si queremos scrollear 2 pixeles, y necesitamos no perder el Carry Flag del primer RL cuando hacemos el segundo? Pues que podemos preservarlo dejándolo en AF' y recuperándolo después: | ||
- | </code> | + | < |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
</ | </ | ||
\\ | \\ | ||
- | **[ [[.: | + | **[ [[.: |