Lenguaje Ensamblador (ASM)

Interpretación en el mundo GBA

¿Qué es el Lenguaje Ensamblador?

El lenguaje ensamblador es un tipo de lenguaje de bajo nivel utilizado para escribir programas informáticos, y constituye la representación más directa del código máquina específico para cada arquitectura de computadoras legible por un programador.
Fue usado ampliamente en el pasado para el desarrollo de software, pero actualmente sólo se utiliza en contadas ocasiones, especialmente cuando se requiere la manipulación directa del hardware o se pretenden rendimientos inusuales de los equipos.

Cuando vamos a referirnos al ASM en GBA nos referimos a aquel lenguaje que nos permite trabajar de una forma eficaz y directa los datos internos de un rom, aquellos que no podemos modificar con las herramientas, que hasta el momento, utilizamos para la edición de los ROMS de GBA. Con el ASM podemos realizar infinidad de aplicaciones en nuestros ROMS.
Ahora explicaremos que son los registros, que en base a ellos podremos generar nuestras rutinas.

Registros

Los registros son empiezan desde r0 hasta r15:

  • r0 – r12: Son registros de usos generales, estos registros son los que podemos en nuestras rutinas con el fin de asignar direcciones, valores o simplemente sobrescribir un valor previamente dado.
  • r13: Es usado como puntero cabezal, aunque si no usas un puntero cabezal, puede usarse como un registro general
  • r14: Es un registro de unión, aunque puede ser usado como un registro general, pero su propósito principal es guardar direcciones previas o llamar sub - rutinas
  • r15: Registro interno de la CPU para comprender los datos editados (No se usa en las rutinas, a excepción de una rutina especial)

Vamos a Entender el ASM

En este tutorial les explicaré las instrucciones (Comandos, como se llamaría en scripts) necesarias para poder generar una rutina.

En este tutorial usaré el Advance Gold Road 2.1 que lo pueden descargar de Pokehacking (Pagina italiana).

Advance Gold Road 2.1

El Advance Gold Road 2.1 te permite cargar los valores asignados  a las variables desde el inicio de tu rutina de la forma:

@define Offset = 0xOffset
@define Valore = 0xValore
Y  todas las demás que necesitemos….

Esto nos permite cargar valores a las variables.

Ejemplo: @define var1 = 0x02020202

De esta forma asignamos el valor “02020202” a “var1”

Después de haber asignado todas las variables que necesitemos vamos a empezar nuestra rutina con:

@thumb: Esto es tan similar como nuestro famoso #org que usamos en nuestros scripts.

Ahora necesitamos definir los registros que deseamos utilizar, y hay dos formas de realizar esto por medio de la instrucción:

Push

  • push {lr}: Esta forma te permite usar los registros sin necesidad de registrarlos
  • push {r0,r1,lr}: Esta forma nos permite asignar los registros que vamos a utilizar empezando desde le menor hasta el mayor. Si deseamos definir los registros desde r0 hasta r4, hacemos lo siguiente: push {r0,r4,lr}

Ahora que ya tenemos claro como inicia una rutina en ASM utilizando el AGR 2.1, aprenderemos como terminarla:

@define Offset = 0xOffset
@define Valore = 0xValore

@thumb
push  {r0,r1,lr}
Acá  estará nuestra rutina
pop  {r0,r1,pc}

Ahora como nos dimos cuenta, la instrucción “pop” maneja la misma escritura que la instrucción “thumb”, es decir debemos poner al final los registros utilizados, pero esta vez cambiamos “lr” por “pc”. También si deseamos usar nuestra rutina sin asignar unos registros específicos.

@define Offset = 0xOffset
>@define Valore = 0xValore

@thumb
push  {lr}
Aca  estará nuestra rutina
pop  {pc}

Simplemente solo dejamos en “thumb”  “lr” y en “pop” “pc”.

Comandos que usaremos en nuestras primeras rutinas.

Cuando usamos una instrucción, sea la que sea, debemos asignarle un registro, y si es el caso una variable o un valor que deseamos que escriba el registro.
 
LDR

Esta instrucción es multipropósito, pero su principal propósito es cargar (leer) una dirección
Ejemplo:

  • ldr r0, =0x02000000 – De esta forma hacemos que se lea en r0 el valor “02000000”
  • ldr r0, [r6]: De esta forma r0 lee el valor que está guardado en r6.
  • ldr r0, [r0, r2]: De esta forma hacemos que r0= r0+r2. El registro que está afuera de las llaves es el registro al que se le asignara la suma de r0+r2.
  • ldr r0, [r6], #0x4: De esta forma hacemos que nuestro r, lea el registro r6 adicionándole un valor en bytes. r6= r6+4. De esta forma r0 ya no solo leerá a r6 como solo el valor que tiene asignado sino que leerá a r6+4 bytes de mas. Ejemplo: digamos que r6 tiene asignado el valor de “0x02000000” entonces: r6 = [r6]”0x02000000” + 4.
  • ldr r0, #0x4: De esta forma hacemos que r0, lea el valor 4. Los valores deben ser dados en hexadecimal.

Cuando queremos que nos cargue un byte que está en cierta dirección, y que NO nos cargue la dirección como tal hacemos lo siguiente:

  • ldrb r6, [r2]: De esta forma si en la dirección 0x02000000 esta asignado el byte 05, entonces nos leerá solo el valor 05, mas no la dirección 0x02000000 como tal. Es de demasiado uso si queremos obtener una cantidad de una dirección en una rutina (Nº de pokes, Nº de mini)
  • ldrh r6, [r2]: De esta forma ya no cargamos solo un byte, sino dos bytes. Por ejemplo si en [r2] que posee la dirección 0x02000000 esta 0504, entonces ya no cargara la dirección en r6, sino solo esta halfword(2 bytes).

STR

Esta instrucción nos permite, guardar en un registro el valor de otro registro para ser utilizado posteriormente.

  • str r0, #0x4: De esta forma se guarda en r0 el valor 4.
  • str r0, [r2]: De esta forma se guarda en r0 el valor de r2.
  • strb r0, [r2]: De esta forma si en la dirección 0x02000000 esta asignado el byte 05, entonces nos guardará solo el valor 05, mas no la dirección 0x02000000 como tal. Es de demasiado uso si queremos obtener una cantidad de una dirección en una rutina (Nº de pokes, Nº de mini)
  • strh r0, [r2]: De esta forma ya no guardaremos solo un byte, sino dos bytes. Por ejemplo si en [r2] que posee la dirección 0x02000000 esta 0504, entonces ya no guardará la dirección en r6, sino solo esta halfword(2 bytes).

Mov

Esta instrucción nos permite escribir en un registro un valor, una dirección o lo que queramos.

  • Mov r0, #0x5: De esta forma escribimos en r0 el valor 5.
  • Mov r0, r1: De esta forma escribimos en r0, los datos que estén guardados en r1.

Add

Esta instrucción nos permite “sumar” en un registro.

  • add r0, r0, r1 - add r0, r0, #0x4: De esta forma hace que nuestro r0 tome el valor de r0 = r0 + r1 o de r0 = r0 + 4, dependiendo de la forma que lo formulemos.

 

Sub

Esta instrucción nos permite “restar” en un registro.

  • sub r0, r0, r1 - sub r0, r0, #0x4: De esta forma hace que nuestro r0 tome el valor de r0 = r0 - r1 o de r0 = r0 -  4, dependiendo de la forma que lo formulemos.

 

Cmp

Esta instrucción nos compara valores entre registros, o entre un registro y un valor.

  • Cmp r0, r1: De esta fomra compara r0 con r1
  • Cmp r0, #0x4: De esta forma compara a r0 con r1

 

 

b (Parecido a un goto en nuestros scripts) 

Esta instrucción nos permite saltar a otra instancia de nuestra rutina, ya sea con una condición o no

La instrucción “b” maneja las siguientes siglas

Sigla

Significado

 EQ

 igual

 NE

 distinto

 LT

 menor

 GT

 mayor

 GE

 Mayor o igual

 LE

 Menor o igual

Tabla tomada de Pokehacking.

Para usarlo usamos la siguiente formulación.

Cpm  r0,r1
bEQ  parte2

parte2:
bla  bla bla
pop  {pc}

Si la condición nos muestra que nos da igual nos envía a la parte dos de nuestra rutina.

Nuestra Primer Rutina

@define lapices = 0x1
@define cuaderno = 0x2
@define dinero = 0x3

@thumb
push {lr}
str r0, lápices ‘ Se carga en r0 el valor de los lápices “1”
str r1, cuaderno ‘Se carga en r1 el valor del cuaderno “2”
str r2, dinero ‘Carga en r2 la cantidad de dinero que tenemos “3”
add r0, r0, r1 ‘Se suman los costos de los lápices y el cuaderno y se guarda en r0”
cmp r0, r2 ‘ compara el costo total con el dinero disponible (r0 y r2)
bEQ comprar ‘Si el costo total es igual al dinero disponible entonces vamos a comprar

comprar:
mov r4, r0 ‘Compramos los productos en la tienda y quedan registrados (r4)
pop { pc}