cursos:ensamblador:aritmetica

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:aritmetica [02-02-2024 10:03] – [Aritmética con el Z80] sromerocursos:ensamblador:aritmetica [02-02-2024 10:12] (actual) – [Números aleatorios] sromero
Línea 13: Línea 13:
 En algunas ocasiones se incluirán comentarios sobre cómo opera esta rutina, y en otras simplemente citaremos la rutina con sus parámetros de entrada y salida para poder usarla en nuestros programas. Para toda rutina, se citará la fuente de la que se ha extraído si es conocida, y su autor (si es posible) para darle su merecido crédito por ella. En algunas ocasiones se incluirán comentarios sobre cómo opera esta rutina, y en otras simplemente citaremos la rutina con sus parámetros de entrada y salida para poder usarla en nuestros programas. Para toda rutina, se citará la fuente de la que se ha extraído si es conocida, y su autor (si es posible) para darle su merecido crédito por ella.
  
-Las rutinas se reproducen tal cual aparecen en la web, por lo que es posible que alguna de ellas incluyan ''PUSH''es y ''POP''para preservar registros, y otras no lo hagan. Debido a esto, cuando vayamos a incorporarlas en nuestros programas o librerías se recomienda que se revise la rutina para añadir o quitar la preservación de registros según la necesitemos o no.+Las rutinas se reproducen tal cual aparecen en la web, por lo que es posible que alguna de ellas incluyan varios ''PUSH'' y ''POP'' para preservar registros, y otras no lo hagan. Debido a esto, cuando vayamos a incorporarlas en nuestros programas o librerías se recomienda que se revise la rutina para añadir o quitar la preservación de registros según la necesitemos o no.
  
 Se recomienda al lector que se desarrolle su propia librería ''aritmetica.asm'' con una selección de rutinas de esta página, eligiendo aquellas rutinas que pueda necesitar en sus programas, y las aproveche en lugar de intentar "reinventar la rueda" y escribir rutinas de aritmética que puedan ser más lentas que las presentadas. Se recomienda al lector que se desarrolle su propia librería ''aritmetica.asm'' con una selección de rutinas de esta página, eligiendo aquellas rutinas que pueda necesitar en sus programas, y las aproveche en lugar de intentar "reinventar la rueda" y escribir rutinas de aritmética que puedan ser más lentas que las presentadas.
Línea 47: Línea 47:
     ld b, 0     ld b, 0
     ld c, a     ld c, a
-    adc hl, bc            ; HL = HL+A +    add hl, bc            ; HL = HL+A 
          
     ; Sumas de registros de 8 bits a registros de 16 bits: OPCION 2     ; Sumas de registros de 8 bits a registros de 16 bits: OPCION 2
Línea 163: Línea 163:
 </code> </code>
  
-Si hubiéramos necesitado multiplicar por 21 o por 19 (por ejemplo), podríamos haber guardado el valor de A antes de este proceso (por ejemplo en el registro C) y haber después sumado o restado C a la multiplicación por 20 para encontrar el valor deseado. Para multiplicar por 22 o por 18 podríamos haberlo sumado restado 2 veces al resultado, etc.+Si hubiéramos necesitado multiplicar por 21 o por 19 (por ejemplo), podríamos haber guardado el valor de A antes de este proceso (por ejemplo en el registro C) y haber después sumado o restado C a la multiplicación por 20 para encontrar el valor deseado. Para multiplicar por 22 o por 18 podríamos haberlo sumado restado 2 veces al resultado, etc.
  
  Pero volvamos a ''SLA'' para multiplicar por potencias de 2. Hemos dicho que cada vez que multiplicamos con desplazamientos (o con sumas de A), el bit más significativo (bit 7) pasa al Carry Flag. Si hacemos múltiples operaciones sin utilizar ese bit lo "perdemos", ya que el máximo valor que podemos almacenar en A es 255, así que no podemos multiplicar números muy grandes. Para valores grandes necesitaremos usar una pareja de registros de 16 bits, e ir pasando el bit saliente (el Carry Flag) al registro de la parte alta del valor:  Pero volvamos a ''SLA'' para multiplicar por potencias de 2. Hemos dicho que cada vez que multiplicamos con desplazamientos (o con sumas de A), el bit más significativo (bit 7) pasa al Carry Flag. Si hacemos múltiples operaciones sin utilizar ese bit lo "perdemos", ya que el máximo valor que podemos almacenar en A es 255, así que no podemos multiplicar números muy grandes. Para valores grandes necesitaremos usar una pareja de registros de 16 bits, e ir pasando el bit saliente (el Carry Flag) al registro de la parte alta del valor:
Línea 172: Línea 172:
 </code> </code>
  
- Al igual que pasaba con ''add aa'', las sumas de 16 bits con ''add hlhl'' pueden llegar a ser más rápidas (1 byte, y 11 ciclos de reloj) que la combinación de ''sla'' + ''rl'' (4 bytes y 16 ciclos).+ Al igual que pasaba con ''ADD AA'', las sumas de 16 bits con ''ADD HLHL'' pueden llegar a ser más rápidas (1 byte, y 11 ciclos de reloj) que la combinación de ''SLA'' + ''RL'' (4 bytes y 16 ciclos).
  
 Por ejemplo: Por ejemplo:
Línea 203: Línea 203:
 \\ **Dividiendo por potencias de dos**\\  \\ **Dividiendo por potencias de dos**\\ 
  
- Del mismo modo que desplazar a la izquierda es multiplicar, entonces **los desplazamientos a la derecha equivalen a dividir por potencias de 2 (2, 4, 8...)**, mediante la instrucción ''srl'':+ Del mismo modo que desplazar a la izquierda es multiplicar, entonces **los desplazamientos a la derecha equivalen a dividir por potencias de 2 (2, 4, 8...)**, mediante la instrucción ''SRL'':
  
 <code z80> <code z80>
Línea 449: Línea 449:
 De la misma forma que se puede multiplicar con múltiples sumas, también podemos dividir de forma poco eficiente con múltiples restas. De la misma forma que se puede multiplicar con múltiples sumas, también podemos dividir de forma poco eficiente con múltiples restas.
  
-Sin embargo, como ocurría con la multiplicación, lo idea es utilizar algoritmos que no tengan un tiempo de ejecución que dependa linealmente de los valores a dividir.+Sin embargo, como ocurría con la multiplicación, lo ideal es utilizar algoritmos que no tengan un tiempo de ejecución que dependa linealmente de los valores a dividir.
  
-Mostraremos a continuación una rutinas finales de división que podemos incluír en nuestros programas.+Mostraremos a continuación unas rutinas finales de división que podemos incluír en nuestros programas.
  
 \\  \\ 
Línea 591: Línea 591:
 Si hay una funcionalidad que necesitaremos casi con total seguridad para desarrollar un juego es la posibilidad de generar números aleatorios. Si queremos que cada partida sea diferente y que ciertas acciones varíen (como por ejemplo, que en un juego de puzzle no aparezcan siempre las mismas piezas), necesitaremos una fuente de aleatoriedad, una rutina que nos devuelva un número diferente cada vez. Si hay una funcionalidad que necesitaremos casi con total seguridad para desarrollar un juego es la posibilidad de generar números aleatorios. Si queremos que cada partida sea diferente y que ciertas acciones varíen (como por ejemplo, que en un juego de puzzle no aparezcan siempre las mismas piezas), necesitaremos una fuente de aleatoriedad, una rutina que nos devuelva un número diferente cada vez.
  
-Hay varias formas de generar números aleatorios. La primera de ella es utilizar funciones matemáticas que nos devuelve un número diferente de una sucesión cada vez que la llamamos. El problema de las rutinas aleatorias basadas en fórmulas es que la sucesión de números aleatorios suele ser cíclico, es decir, que siempre proporcionan los mismos números y en el mismo orden, a partir de una determinada semilla.+Hay varias formas de generar números aleatorios. La primera de ella es utilizar funciones matemáticas que nos devuelven un número diferente de una sucesión cada vez que la llamamos. El problema de las rutinas aleatorias basadas en fórmulas es que la sucesión de números aleatorios suele ser cíclico, es decir, que siempre proporcionan los mismos números y en el mismo orden, a partir de una determinada semilla.
  
 Veamos una rutina muy simple (extraída de la página //Z80 bits//, de //Milos Bazelides//), que utiliza la fórmula ''x[i + 1] = (5 * x[i] + 1) mod 256''. Es muy simple y de reducido tamaño, pero la serie resultante tiene poca aleatoriedad: Veamos una rutina muy simple (extraída de la página //Z80 bits//, de //Milos Bazelides//), que utiliza la fórmula ''x[i + 1] = (5 * x[i] + 1) mod 256''. Es muy simple y de reducido tamaño, pero la serie resultante tiene poca aleatoriedad:
Línea 615: Línea 615:
 </code> </code>
  
-la rutina utiliza una semilla (RAND_SEED) que inserta en el registro A para realizar una serie de operaciones y generar el siguiente valor de la serie en A.+La rutina utiliza una semilla (RAND_SEED) que inserta en el registro A para realizar una serie de operaciones y generar el siguiente valor de la serie en A.
  
 Al final de la rutina podemos ver cómo hay una instrucción ''ld (Rand8+1),a'' la cual **modifica el propio código** para meter el valor resultante obtenido en el ''ld a, X'' inicial. De este modo, la siguiente vez que llamemos a la rutina tendremos en su primer instrucción el último valor generado, que usaremos como origen de los cálculos para obtener el siguiente. Al final de la rutina podemos ver cómo hay una instrucción ''ld (Rand8+1),a'' la cual **modifica el propio código** para meter el valor resultante obtenido en el ''ld a, X'' inicial. De este modo, la siguiente vez que llamemos a la rutina tendremos en su primer instrucción el último valor generado, que usaremos como origen de los cálculos para obtener el siguiente.
Línea 853: Línea 853:
 \\  \\ 
  
-En realidad, podríamos llegar un capítulo entero de rutinas diferentes para generar números aleatorios, ya que hay decenas en la red usando diferentes técnicas. Por ahora, podemos utilizar cualquiera de las vistas anteriormente en nuestros programas y obtener una más que decente aleatoriedad, ya que alguna de ellas ha sido utilizada en juegos comerciales reales de la época.+En realidad, podríamos llenar un capítulo entero de rutinas diferentes para generar números aleatorios, ya que hay decenas en la red usando diferentes técnicas. Por ahora, podemos utilizar cualquiera de las vistas anteriormente en nuestros programas y obtener una más que decente aleatoriedad, ya que alguna de ellas ha sido utilizada en juegos comerciales reales de la época.
  
 \\  \\ 
  • cursos/ensamblador/aritmetica.1706868197.txt.gz
  • Última modificación: 02-02-2024 10:03
  • por sromero