Registrarse

[ASM] Division de 2 numeros

Sonicarvalho

Tutorial Maker
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:

  • Escoger 2 números para dividir
  • Asignar las variables 8004/8005 con ellos
  • Leer los valores de las variables con una rutina
  • Cargar los registros con ellos
  • Utilizar el SWI
  • Grabar el resultado de la división en la variable 8006
  • En un script utilizar eses valores

Conocimientos necesarios:
  • Scripting
Empezaremos con el script, pues es la fase inicial.
Variable 0x8004 es el numerador, Variable 0x8005 es el denominador.

Seria algo así:
Código:
'---------------
#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 [buffer1]/[buffer2] = [buffer3]
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).

SWI 06h (GBA) or SWI 09h (NDS7/NDS9) - Div
Código:
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.

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

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

Código:
.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:
Código:
.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.

Código:
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.
[caja=][css-h2=]Registros:[/css-h2]
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 -)
[/caja]

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
 
Última edición por un moderador:

Cheve

MoonLover~
Miembro de honor
RE: [ASM]Division de 2 numeros

Wow! o_O

Otro Genial aporte...
Me encantó... y pude entender (después de 15 Minutos, pero al fin y al cabo lo hice) la Rutina ASM. Me ah hecho mucha Ilusión :D

¡Vaya! El SWI tiene muchas funciones... ¡Genial! ¡Cuantas Más Mejor!


Si pongo swi 0x26... ¿El juego se Reinicia?
Bueno... Ahora me mataré pensando como se podría mostrar una Imágen en la Pantalla x'D Haber si lo resuelvo... :)

Muchas Gracias!
Salu2!
 

Sonicarvalho

Tutorial Maker
RE: [ASM]Division de 2 numeros

@Cheve_X
AL FIN ALGUIEN ENTIENDE MIS TUTORIALES!!

Broma (o no) (?)

Si, me alegra que hayas comprendido mi tutorial de SWI. Al fin hay gente que desea aprender algo!

Bueno, si, el SWI 0x26 resetea el juego. El link que yo puse en el fin del tutorial es como una 'biblia' de los asm hackers, contiene todo acerca de Hardware, Asm, I/O, sonido, gráficos, etc para GBA y NDS.

Acerca de la imagen en la pantalla, para eso estan los SWIs 0x11 y 0x12. Para nosotros, principiantes (me incluyo), el 0x12 es el que nos hace el trabajo.

SWI 11h (GBA/NDS7/NDS9) - LZ77UnCompWram
SWI 12h (GBA/NDS7/NDS9) - LZ77UnCompVram


R0 = Source Adress (offset del grafico LZ77)
R1 = Destination adress (offset de destino en la VRAM (06xxxxxx))

Pero debes primero utilizar ese SWI para los tiles y después para el tilemap. La verdad es que mismo yo solo sé utilizar esto de forma muy simples.

Lista de SWIs para quién no percibe el site:
[caja=]
SWI 00h - SoftReset
SWI 01h - RegisterRamReset
SWI 02h - Halt
SWI 03h - Stop
SWI 06h - Div
SWI 07h - DivArm
SWI 08h - Sqrt
SWI 09h - ArcTan
SWI 0Ah - ArcTan2
SWI 0Bh - CpuSet
SWI 0Ch - CpuFastSet
SWI 0Dh - GetBiosChecksum
SWI 0Eh - BgAffineSet
SWI 0Fh - ObjAffineSet
SWI 10h - BitUnPack
SWI 11h - LZ77UnCompWram
SWI 12h - LZ77UnCompVram
SWI 13h - HuffUnComp
SWI 14h - RLUnCompWram
SWI 15h - RLUnCompVram
SWI 16h - Diff8bitUnFilterWram
SWI 17h - Diff8bitUnFilterVram
SWI 18h - Diff16bitUnFilter
SWI 19h - SoundBias
SWI 1Ah - SoundDriverInit
SWI 1Bh - SoundDriverMode
SWI 1Ch - SoundDriverMain
SWI 1Dh - SoundDriverVSync
SWI 1Eh - SoundChannelClear
SWI 1Fh - MidiKey2Freq
SWI 20h..24h - SoundUndocumented
SWI 25h - MultiBoot
SWI 26h - HardReset
SWI 27h - CustomHalt
SWI 28h - SoundDriverVSyncOff
SWI 29h - SoundDriverVSyncOn
SWI 2Ah - SoundGetJumpList
[/caja]
 

Elpollo

BizNieto de la *****!!
Respuesta: [ASM]Division de 2 numeros

Me pregunto si hay alguna forma de ver el codigo de los SWI, para entender como hace la division.
PD: Muchas gracias por el tutorial
 
Arriba