12581-GBA_|_Otros_|_\[ASM]Division_de_2_numeros
#0
Sonicarvalho 17082
Este tutorial es aplicable a cualquier versión, solo cambian los offsets de las variables!

Si os parece que este tutorial es inútil, entonces podréis salir ya de él. ASM es una cosa difícil de se percibir, y lo que cuenta es la experiencia que tienes con el. Tienes que seguir todos los tutoriales que encuentras por el camino. Si no queréis seguir este tutorial porque os parece inútil, entonces olviden aprender ASM. No lo lograrán.


Buenas! Hoy voy a incorporar un nuevo tema en ASM:
Las funciones de la BIOS.

La BIOS es la unidad básica de entrada y salida de la consola (si, tiene que ver con I/O), pero bueno no hablaré específicamente de eso hoy.

Las funciones de la bios (llamadas SWI) sirve para hacer tareas que las instrucciones no hacen normalmente, como por ejemplo poner un grafico LZ77 en la pantalla (como una portada), copiar grandes cantidades de datos de una sitio a otro (ROM a Ram o RAM a VRAM), o hasta mismo la raíz cuadrada, sonidos, etc!
Hoy voy abordar la division, que es una cosa para la cual no existe una instrucción.

Entonces, en este tutorial haremos el siguiente:


Conocimientos necesarios:

Empezaremos con el script, pues es la fase inicial.
Variable 0x8004 es el numerador, Variable 0x8005 es el denominador.

Seria algo así:

'---------------
#org @start
setvar 0x8004 4
setvar 0x8005 2
callasm 0xXXXXXX+1
buffernumber 0x0 0x8004
buffernumber 0x1 0x8005
buffernumber 0x2 0x8006
msgbox @text 0x6
end

#org @text
= Oye,el resultado de / =


Como podemos ver, vamos a dividir 4 por 2. Nada de especial, pero para el efecto del tutorial servirá.
Hacemos con que las variables 8004/8005 tengan los valores para dividir (RECUERDO: 0x8004 es el numerador, 0x8005 es el denominador)

Ahora que nos falta? Los offsets de las variables. Pueden conseguirlos aquí, pero yo postearé aquí los de ruby, que es la version que estamos trabajando (por lastima, aquí solo hay ruby hackers...lll-_-)

Ruby:
Var_8004 - 0x0202E8CC
Var_8005 - 0x0202E8CE
Var_8006 - 0x0202E8D0

Bien, ahora ya estamos listos para empezar nuestra pequeña rutina. Pero antes de todo, una explicación del SWI:
El SWI (software interrupt) es una instrucción que llama las funciones de la bios, y utiliza los valores de r0, r1, r2 y r3 en sus funciones (algunas veces no es necesario todos los registros), que después de la utilización, los registros r0,r1, r3 tienen los valores de retorno (valores que nos interesan o entonces 'lixo'), pero los demás registros quedan intactos (r2,r4...r12).
El SWI que vamos utilizar hoy es el SWI 0x6, el Div, y como registros de entrada sonutilizados r0 (numerador) y r1 (denominador). Los registros de salida (los resultados) tenemos r0 (resultado de la division, POSITIVO ó NEGATIVO), r1 (el resto de la división) y r3 (el valor absoluto de la division).

[persiana=Informaciones sobre el DIV (INGLÉS)]
SWI 06h (GBA) or SWI 09h (NDS7/NDS9) - Div
Signed Division, r0/r1.
r0 signed 32bit Number
r1 signed 32bit Denom
Return:
r0 Number DIV Denom ;signed
r1 Number MOD Denom ;signed
r3 ABS (Number DIV Denom) ;unsigned
For example, incoming -1234, 10 should return -123, -4, +123.
The function usually gets caught in an endless loop upon division by zero.
[/persiana]

A nosotros solo nos interesa el resultado, r0. Eso indica que ya podemos empezar haciendo la rutina.

(...) 2 minutos despues (...)


.align 2
.thumb
.global DivSWI_TUTORIAL

main:
push {r0-r3, lr}
ldr r0, Var_8004
ldr r1, Var_8005
ldrh r0, [r0]
ldrh r1, [r1]
swi 0x6
ldr r2, Var_8006
strh r0, [r2]
pop {r0-r3, pc}

.align 2
Var_8004: .word 0x0202E8CC
Var_8005: .word 0x0202E8CE
Var_8006: .word 0x0202E8D0


Bien, ahora las explicaciones:

.align 2
.thumb
.global DivSWI_TUTORIAL

main:
push {r0-r3, lr}
ldr r0, Var_8004
ldr r1, Var_8005
ldrh r0, [r0]
ldrh r1, [r1]

Esto no explicaré en detalle, si no saben esto, entonces no deberían estar aquí. Hagan el favor de leer los tutoriales de ~Javs y Hackmew.
Básicamente carga los valores de las variables 8004/5 a los registros de numerador(r0) y denominador(r1).

En este punto, ya tenemos los valores de las variables 8004 y 8005 dondo nosotros queremos: los registros r0 y r1, (numerador y denominador). Ahora estamos prontos para llamar el SWI 0x6.
La instrucción SWI es como un callstd en scripting.

swi 0x6
ldr r2, Var_8006
strh r0, [r2]
pop {r0-r3, pc}

Ahora llamamos el SWI, y cargamos el offset de la variable 8006 y grabamos allá el resultado de la division.

Registros:

Antes del SWI (division) los registros són:
r0 = 4 (numerador)
r1 = 2 (divisor)
r2 = 0 (no utilizado)
r3 = 0 (no utilizado)

Después:
r0 = 2 (resultado)
r1 = 0 (resto)
r2 = 0 (no utilizado)
r3 = 2 (resultado absoluto (sin sinales + o -)



Ok. Ahora compilaremos la rutina en un offset de la rom terminado en 0, 4, 8 o C, y llamamos el script del inicio del tutorial!

Aquello que deben percibir de este tutorial es como utilizar SWIs, no como 'Dividir' propriamente. Para utilizar SWIs, saiban primero lo que cada SWI hace: Lista de funciones

Made by Sonicarvalho/Dark Ray
Dar creditos/ + Gracias/ Comenten! :D