Registrarse

[ASM] Clase 3: Instrucciones Básicas

Cheve

MoonLover~
Miembro de honor
Clase Número 3

Se recomienda leer las clases anteriores, disponibles en el final del post.

¡Que tal gente! :awesome:
Retomemos dónde nos habíamos quedado anteriormente, que fue en los Registros del Procesador.

Recordemos:
  • 16 registros de 32 Bytes cada uno (Hasta 0xFFFFFFFF).
  • R0 a R7 Lo-Registers (Registros Bajos)
  • R8 a R12 Hi-Registers (Registros Altos)
  • R13 Stack Pointer (SP)
  • R14 Link Register (LR)
  • R15 Program Counter (PC)

Los conceptos de cada uno de ellos están en la clase anterior y entenderlos es bastante importante, aunque seguramente deberán (deberemos) ir a la clase anterior para releer varias cosas allí explicadas.

También tengamos en cuenta ésta notación:

Rd = Registro Destino.

Rm/Rn = Registro Normal

#0xZZZZZZ = Numero fijo

Empecemos con ésta clase:

Instrucciones Principales: Push y Pop

¿Recuerdan el Concepto de Pila? - Pues más les vale que lo hagan xD

Push:

Uso: Push - o empujar - almacena en una pila los valores de los registros dentro de los corchetes {}, y los deposita en el Stack - o pila - de nuestro procesador. Se usa en el 90% de los casos al hacer una rutina, y es lo primero que se escribe de la misma.

Sintaxis: Push { Lista de Registros, LR}

Ejemplo: Push {R0, R1, R2, R3, LR} ; Push {R0-R3,LR}

*Nota: Ambos ejemplos son equivalentes e igualmente válidos.

¿Para qué?: Para que al terminar nuestra rutina, con otra instrucción, podamos volver todo a "como estaba antes"

Pop:

Uso: Pop - o sacar - saca de la pila los valores almacenados de los registros dentro de los corchetes {}, y los carga en memoria. Se usa en el 90% de los casos al hacer una rutina, y es lo último que se escribe de la misma. (Siempre que haya un Push deberá haber un Pop).

Sintaxis: Pop { Lista de Registros, PC}

¿Para qué?: Para que al terminar nuestra rutina volvamos todo a "como estaba antes". (Cargamos lo que almacenó el Push, así puede seguir adelante la Rom desde donde estaba)



Instrucciones de Cálculo

Add

Uso: Sumar valores entre registros o sumar un registro con un valor.

Sintaxis:
  • Add Rd, #0xZZ Donde 0xZZ tiene que estar entre 0x0 y 0xFF (Suma directa de un valor). Resultado: Rd = Rd + 0xZZ
  • Add Rd, Rn (Suma entre dos registros, con asignacion del valor al primero). Resultado: Rd = Rd + Rn.
  • Add Rd, Rn, #0xZZ Donde 0xZZ tiene que estar entre 0x0 y 0xFF (Suma entre un registro y un valor). Resultado: Rd = Rn + 0xZZ.
  • Add Rd, Rn, Rm (Suma entre dos registros). Resultado: Rd = Rn + Rm.


Sub

Uso: Restar valores a los registros o restar valores entre registros.

Sintaxis:
  • Sub Rd, #0xZZ Donde 0xZZ tiene que estar entre 0x0 y 0xFF (Resta directa de un valor). Resultado: Rd = Rd - 0xZZ
  • Sub Rd, Rn (Resta entre dos registros, con asignacion del valor al primero). Resultado: Rd = Rd - Rn.
  • Sub Rd, Rn, #0xZZ Donde 0xZZ tiene que estar entre 0x0 y 0xFF (Resta entre un registro y un valor). Resultado: Rd = Rn - 0xZZ.
  • Sub Rd, Rn, Rm (Resta entre dos registros). Resultado: Rd = Rn - Rm.



Mul

Uso: Multiplica Registros.

Sintaxis: Mul Rd, Rn . Resultado: Rd = Rd * Rn



Instrucciones de Carga de Datos

Ldr (Load Register)

Uso: Carga un valor de 4 Bytes directamente en el registro (Desde 0x00000000 hasta 0xFFFFFFFF).

Sintaxis:

  • Ldr Rd, [Rn] Resultado: Rd = Rn
  • Ldr Rd, =(0xFFFFFFFF) Resultado: Rd = 0xFFFFFFFF
  • Ldr Rd, [Rn, #0xFF] Resultado: Rd = Rn + 0xFF

Ldrh (Load Register Half-Word)
Uso: Carga un valor de 2 Bytes directamente en el registro (Desde 0x0000 hasta 0xFFFF).

Sintaxis:

  • Ldrh Rd, [Rn] Resultado: Rd = Rn
  • Ldrh Rd, =(0xFFFF) Resultado: Rd = 0xFFFF
  • Ldrh Rd, [Rn, #0xFF] Resultado: Rd = Rn + 0xFF

Ldrb (Load Register Byte)
Uso: Carga un valor de 1 Byte directamente en el registro (Desde 0x00 hasta 0xFF).

Sintaxis:

  • Ldrb Rd, [Rn] Resultado: Rd = Rn
  • Ldrb Rd, =(0xFF) Resultado: Rd = 0xFF
  • Ldrb Rd, [Rn, #0xFF] Resultado: Rd = Rn + 0xFF

_________________________________________

Str (Store Register)

Uso: Carga en una dirección 4 Bytes de data. La dirección es dada por el registro entre corchetes mientras que el otro es el que contiene la data.

Sintaxis:

  • Str Rd, [Rn] Rn = Rd (Si Rn = 0x02303000, en ese offset se escribirá lo que contiene Rd)
  • Str Rd, [Rn, #0xFF] [Rn + 0xFF] = Rd (Si Rn = 0x02303000, en ese offset + 0xFF (0x023030FF) se escribirá lo que contiene Rd)

Strh (Store Register Half-Word)

Uso: Carga en una dirección 2 Bytes de data. La dirección es dada por el registro entre corchetes mientras que el otro es el que contiene la data.

Sintaxis:

  • Strh Rd, [Rn] Rn = Rd (Si Rn = 0x02303000, en ese offset se escribirá lo que contiene Rd)
  • Strh Rd, [Rn, #0xFF] [Rn + 0xFF] = Rd (Si Rn = 0x02303000, en ese offset + 0xFF (0x023030FF) se escribirá lo que contiene Rd)

Strb (Store Register Half-Word)

Uso: Carga en una dirección 1 Bytes de data. La dirección es dada por el registro entre corchetes mientras que el otro es el que contiene la data.

Sintaxis:

  • Str Rd, [Rn] Rn = Rd (Si Rn = 0x02303000, en ese offset se escribirá lo que contiene Rd)
  • Str Rd, [Rn, #0xFF] [Rn + 0xFF] = Rd (Si Rn = 0x02303000, en ese offset + 0xFF (0x023030FF) se escribirá lo que contiene Rd)

Parte Práctica:


Inauguramos ésta sección en las clases/tutoriales realizando... ¡Nuestra primer rutina!

Vamos a usar el compilador de HackMew (Adjunto al final del tema) por lo que usaremos ésta plantilla por ahora:

Código:
.text
.align 2
.thumb
.thumb_func
.global Rutina_1

main:


@Aquí irá nuestra rutina


.align 2

@Aquí declararemos nuestras variables, en caso que necesitemos hacerlo
.text
.align 2
.thumb
.thumb_func

Son instrucciones que le dicen al compilador que estamos trabajando en thumb y alinea los bytes para ésto.

.global Rutina_1

Es opcional, sólo para darle un nombre a nuestra rutina

main:

Es una etiqueta, puede ser main: ; pepino: ; aca_empieza_mi_rutina_xdxd:
siempre terminada por " : " .

Para empezar a escribir nuestra rutina, primero necesitamos una idea, ¿A que si? xD

Pues recientemente quise hacer un script en el cual no me dejen entrar a una cueva hasta que mi pokémon tenga cierto nivel, pero no existe algo como un "GetPokemonLevel", así que lo haremos nosotros.

Entonces tenemos el primer paso:

1.Tener la Idea

El segundo paso sería obtener la mayor información posible del tema que nos atañe (Más adelante habrá una clase dedicada al 100% a ésto), para así saber o tener idea de como hacerlo y también si es posible de alguna manera.
Éste es un ejemplo simple, ya que sabemos que el nivel del pokémon ya está ahí, es solo extraerlo, meterlo en una variable y jugar con él.
¿Pero dónde está? Aquí entra nuestra amiga: Bulbapedia !

De aquí sacamos los datos para nuestra base, siendo así:


FR: 0x02024284

EM: 0x020244EC

RY: 0x03004360

Y luego tenemos una muy bonita tabla a la derecha:



Ésta tabla, nos explica fácilmente que, a partir de la dirección dada para nuestra base, tenemos distintos "Offsets" para cada dato particular de nuestro pokémon. (Nota: Los "Offsets" en la tabla están en decimal)

A nosotros nos interesa el offset del nivel,por lo que haremos lo siguiente:

FR: 0x02024284 + 0x54 (84 en Hex)

EM: 0x020244EC + 0x54 (84 en Hex)

RY: 0x03004360 + 0x54 (84 en Hex)


Quedándonos con los offset:

0x20242D8 --> Level primer pokémon en la party

0x2024540 --> Level primer pokémon en la party

0x03004360 --> Level primer pokémon en la party

Anotemos también por ahí:

Data total que hace a un pokémon: 100 Bytes

Direccion de la variable 0x800D en la Ram: 0x020270B6 + (0x800D * 2) (Gracias HackMew)

Direccion de la variable 0x800D en la Ram: 0x020275D6 + (0x800D * 2) (Gracias HackMew)


Direccion de la variable 0x800D en la Ram: 0x0201E8C2 + (0x800D * 2) (Gracias HackMew)


Bueno, y ya tenemos todo lo que necesitamos, copiemos la plantilla:
(Yo la escribiré para FR, pero será cuestión de cambiar el valor de las variables)

Código:
.text
.align 2
.thumb
.thumb_func
.global Rutina_1

main:
	push{r0-rx, LR} @Aún no sabemos cuántos registros usaremos
	
	pop {r0-rx, PC} 

.align 2



Código:
.text
.align 2
.thumb
.thumb_func
.global Rutina_1

main:
	push{r0-rx, LR}

	
	pop {r0-rx, PC} 

.align 2

.VAR:                            @De ésta forma declaramos que cada
	.word 0x020270B6 + (0x800D * 2)     @ vez que escribamos "VAR" nos referimos
                                                   @a dicha dirección

.PokemonLevel:
	.byte 0x20242D8

Código:
.text
.align 2
.thumb
.thumb_func
.global Rutina_1

main:
	push{r0-rx, LR}
	ldr r0, .PokemonLevel     [MENTION=28468]car[/MENTION]go en r0 el valor de la variable "PokemonLevel" r0 = 0x020242D8
	ldr r1, .VAR              [MENTION=28468]car[/MENTION]go en r1 el valor de la variable "VAR" r1 = 0x020370D0
	ldrb r0, [r0]	    [MENTION=28468]car[/MENTION]go en r0 el valor byte que contiene el offset que contiene r0 (El lvl del primer pokémon)
	strb r0, [r1]               [MENTION=28468]car[/MENTION]go en el offset que contiene r1 el valor byte que contiene r0   
	pop {r0-rx, PC} 

.align 2

.VAR:                            
	.word 0x020270B6 + (0x800D * 2)
.PokemonLevel:
	.byte 0x020242D8

Código:
.text
.align 2
.thumb
.thumb_func
.global Rutina_1

main:
	push {r0-r1, lr} @Arreglamos el push y el pop
	ldr r0, .PokemonLevel
	ldr r1, .VAR
	ldrb r0, [r0]
	strb r0, [r1]
	pop {r0-r1, pc} 

.align 2

.VAR:                            
	.word 0x020270B6 + (0x800D * 2)
.PokemonLevel:
	.byte 0x020242D8

Y listo, ya tenemos nuestra rutina lista para compilar y probar

Código:
#dynamic 0x800000

'---------------
#org @start
callasm 0x8900001
buffernumber 0x0 LASTRESULT
msgbox  [MENTION=29127]String[/MENTION]1 MSG_FACE '"Nivel del 1er pokémon: [buffer1]"
end


'---------
' Strings
'---------
#org  [MENTION=29127]String[/MENTION]1
= Nivel del 1er pokémon: [buffer1]

Tarea: - Hacer que ésta rutina sirva para cualquier pokémon X de la party :D

Pista: Se puede usar la var 0x800D para ingresar un valor.

_____________________________

Clases Anteriores:

Clase 0 - Comprendiendo lo muy muy básico

Clase 1 - Comprendiendo lo Básico

Clase 2 - Registros, conociendo al procesador.

Clase Número 3: Instrucciones Básicas
 
Última edición:

FEL!X

ᴛᴜ ᴀᴍɪɢᴏ ᴇʟ ᴇsᴘᴀᴅᴀᴄʜíɴ
Usuario de Oro
Respuesta: GBA | ASM | Clase Número 3: Instrucciones Básicas

¡Yeaah! ¡La Instrucciones básicas! ¡Que grande eres!

Me he releído los temas anteriores y me he mirado a fondo las lecciones tomándome mi tiempo. Es una pasada, aunque admito que me ha costado entenderlo de primeras, le he dado muchas vueltas (risas).A continuación te voy a dejar unas “pocas” dudas o anotaciones por si me podrás ayudar ya que seguramente las dudas que tenga yo también las va a tener otro.

  • 1) El concepto más difícil de entender para mí ha sido comprender por qué usar la pila con el método Push-Pop o no . Te explico cómo lo entiendo yo, a ver si me equivoco o no:

Por lo que entiendo, lo que hacemos con push es hacer copia de los datos del los registros que vamos a usar. De esta forma manipulamos los registros a la vez que tenemos una copia de ellos en la pila. Cuando hemos terminado de usar los registros los restablecemos con el pop. De éste modo, usar Push y Pop nos sirve para utilizar los registros en un momento dado pero dejándolos al final de igual manera que al principio.

Por cierto, el gif va muy rápido y se hace difícil de comprenderlo, es mejor usar imágenes por pasos, como en la lección anterior.

  • 2) Las instrucciones de cálculo a simple vista creo que son fáciles de entender. Los Add/Sub Rd, Rn, Rm son sumas/restas entre dos registros cuyo valor está definido previamente ¿no?

Te pongo un ejemplo de cómo lo he entendido. Imaginémonos que quiero que pase algo dependiendo de que la suma entre valor de ataque y defensa del primer pokemon del equipo sea valor:

Offsets:
Código:
FR: [COLOR="Red"]0x02024284[/COLOR] (pokemon data estrucutre offset) sabiendo que 0x84 es 132 en decimal:

Offset del valor de ataque: = [B][COLOR="Red"] 0x02024200 +0x84 + 0x5A[/COLOR][/B] (90 en Hex)=
= [B][COLOR="Red"]0x02024200 + 0xDE[/COLOR][/B] (132+90= 222 en decimal) = [B][COLOR="Red"]0x020242DE[/COLOR][/B]


Offset del valor de defensa =[B] [COLOR="Red"]0x02024200 +0x84 + 0x5C[/COLOR][/B] (92 en Hex) =
=[B][COLOR="Red"] 0x02024200 + 0xE0[/COLOR][/B] (132+92= 224 en decimal) = [B][COLOR="Red"]0x020242E0[/COLOR][/B]
Rutina:
Código:
.text
.align 2
.thumb
.thumb_func
.global Rutina_1

main:
	push {r0-r3, lr} 
ldr r0, .PkAttack
ldr r1, .PkDefense
ldr r2, .VAR
ldrb r0, [r0]
ldrb r1, [r1]
[COLOR="Red"][B]add r3, r0, r1[/B][/COLOR]
strb r3, [r2]
	pop {r0-r3, pc} 

.align 2

.VAR:                            
	.word 0x020270B6 + (0x800D * 2)
.PkAttack:
	.byte [B][COLOR="Red"]0x020242DE[/COLOR][/B]

.PkDefense:
	.byte [B][COLOR="Red"]0x020242E0[/COLOR][/B]

Planteado de esta forma ¿Mi rutina sería correcta?
Pd:¡Mi primera rutina wii! (risas)

Otras dudas relacionadas con el tema de las instrucciones son: (1) en caso de restar dos registros y el resultado sea inferior a cero (número negativo), ¿Qué ocurre con el valor? Y por otra parte (2) en caso de multiplicar dos números y el resultado decimal sea mayor a 255 es decir 0xFF para arriba (sea 0x 100, 0x101, 0x102…)

  • 3) En cuanto a las instrucciones de carga de datos creo que las he entendido (aunque me ha costado bastante xD). Aunque me gustaría confirmar si estoy en lo cierto: ¿Al cargar con un load los bytes se cargan en línea empezando por la izquierda? ¿También se leen por la izquierda?
Es decir:
Código:
ldr r0, 0xAABBCCDD 	
[COLOR="Red"]Registro 0 = DD CC BB AA	[/COLOR]
 
ldr r0, 0xEE
[COLOR="Red"]Registro 0 = EE DD CC BB AA[/COLOR]

ldr r1,r0
[COLOR="Red"]Registro 0 = EE DD CC BB AA
Registro 1 = EE
[/COLOR]


Bueno, pos eso es todo, creo que no me dejo nada por preguntar (de momento x’D). Perdóname eh. Ya sabes que mis preguntas las hago con mucho amor.

* * *​

Ha sido un tuto genial Cheve. Me lo he pasado genial leyendo e intentando entender sobre la materia. Investigando y al fin al cabo con el fin de comprenderlo todo a mi manera. Espero haber sido claro y que me puedas ayudar a entenderlo para saber si estoy en el buen camino (o si soy un fracaso D': y doy asco en ASM ).

Muchísimas gracias por el aporte, espero que haiga más en un futuro y así poder continuar de tanto en tanto en esta parte del romhacking en la que también me gustaría poder defenderme.


¡Un abrazo Cheve/ @MoonLover[/MENTION] !

Pd: Cuando tenga la tarea la postearé por aquí a ver qué tal.
Pd2: Perdón por ser tan largo como siempre, me enrollo más que una persiana. Pero ya sabes, lo hago con mucho hamorrrg
 

FEL!X

ᴛᴜ ᴀᴍɪɢᴏ ᴇʟ ᴇsᴘᴀᴅᴀᴄʜíɴ
Usuario de Oro
Respuesta: GBA | ASM | Clase Número 3: Instrucciones Básicas

Código:
.text
.align 2
.thumb
.thumb_func
.global Rutina_1

main:
	push {r0-r1, lr} 
	ldr r0, .PokemonLevel
	ldr r1, .VAR
	ldrb r0, [r0]
	strb r0, [r1]
	pop {r0-r1, pc} 

.align 2

.VAR:                            
	.word 0x020270B6 + (0x800D * 2)
.PokemonLevel:
	.byte 0x020242D8
Tarea: - Hacer que ésta rutina sirva para cualquier pokémon X de la party :D

Pista: Se puede usar la var 0x800D para ingresar un valor.
Mmm, no estoy seguro. Pero si tuviera que hacerlo supongo que haría primero un script donde guardara en 0x800D (Lastresult) el slot/ubicación del pokemon que estoy eligiendo.

Como sabemos que los pokemons se eligen en 6 slots empezando por el primero =0x0 y terminando en 0x5, el valor de 0x800D será en este rango de valores.

Sabemos que el data de un pokemon ocupa 100 bytes en decimal, es decir 0x64 por lo que si el data del level del primer pokemon es 0x020242D8, el del segundo (0x1) será 0x020242D8 + 0x64.

Sabiendo que el incremento es el mismo, concluimos que:
Offset de data de level del pokemon y= 0x020242D8 + 0x64*y


Por lo tanto, todo lo que tenemos a continuación son simples mates. Solo tenemos que decidir “y” (=slot del pokemon) y sacar el byte que es el nivel que queremos guardar en la misma 0x800D al final de la rutina para poder usarlo en el juego.

La rutina que propongo entonces es:

Código:
.text
.align 2
.thumb
.thumb_func
.global Rutina_1

main:
	push {r0-r2, lr} 
	ldr r0, .PokemonLevel
	ldr r1, .VAR
[COLOR="Red"][B]	ldrb r2, .PokemonIncrementoLevel
	ldrb r1, [r1]
	mul r2, r1
	add r0, r2[/B][/COLOR]
	ldrb r0, [r0]	
	strb r0, [r1]
	pop {r0-r2, pc} 

.align 2

.VAR:                            
	.word 0x020270B6 + (0x800D * 2)
.PokemonLevel:
	.byte 0x020242D8 

.PokemonIncrementoLevel:
	.byte 0x64
Como vemos en rojo tenemos una parte diferente respecto a la rutina que solo funciona para el primer poke a modo de ejemplo dada por Cheve.

En éste caso usamos un registro mas, r2, por lo que usamos en total 3 registros; r0,r1yr2. El paso en rojo consiste en cargar el valor del LASRESULT guardado en el registro 1, multiplicarlo por el incremento y sumárselo al offset. Es decir, la ecuación que expliqué antes:
Offset de data de level del pokemon y= 0x020242D8 + 0x64*y

Y eso es todo, la continuación es la misma que en el la rutina únicamente válida para el primer poke. El byte de nivel se carga dependiendo de la dirección del slot dada y y se guarda en 0x800D para su posterior uso.

* * *
Y esto es todo, tarea presentada lista para revisar maestro Cheve. ¡Gracias por la lección jefe!

Un abrazo. :)


Pd: Cheve, ahora tienes pendiente los dos posts del tema x’D. Quería esperar para añadir la tarea pero…no C:

Pd2: Espero que te guste mi tarea. Ya sabes, lo hago con cariño x’D
 

Cheve

MoonLover~
Miembro de honor
Respuesta: GBA | ASM | Clase Número 3: Instrucciones Básicas

@FEL!X, no he compilado las rutinas, pero no te haz equivocado en nada y deberían funcionar ambas.
Nada que corregirte, lo de la pila lo haz entendido perfe C:


Sólo una cosa, aunque aún no haya explicado como hacerlo, debes tener en cuenta que la Var 0x800D en realidad no está limitada a un valor entre 0x0 y 0x5, por lo que ahí podría generar un error, pero luego habrá otra clase donde se controlará eso.

Gracias por ir siguiendo las clases! :D

PD: Recién cuando ví tu mensaje estoy terminando de montar el Windows7 xD
 

FEL!X

ᴛᴜ ᴀᴍɪɢᴏ ᴇʟ ᴇsᴘᴀᴅᴀᴄʜíɴ
Usuario de Oro
Respuesta: GBA | ASM | Clase Número 3: Instrucciones Básicas

FEL!X, no he compilado las rutinas, pero no te haz equivocado en nada y deberían funcionar ambas.
Nada que corregirte, lo de la pila lo haz entendido perfe C:
¡Yeeeah! Te loveo. Me alegra oírlo. Me mola pensar que estoy siguiendo el hilo de las lecciones.

Sólo una cosa, aunque aún no haya explicado como hacerlo, debes tener en cuenta que la Var 0x800D en realidad no está limitada a un valor entre 0x0 y 0x5, por lo que ahí podría generar un error, pero luego habrá otra clase donde se controlará eso.
He tenido en cuenta el Lastresult porque lo tenía a mano, tienes toda la razón. Para este caso también podría haber usado en su lugar cualquier variable segura. El tema de esto es ver si la var 0x800D se toca con ello sí, tendre en cuenta el peligro ;) Gracias por remarcarlo

* * *​

Relacionado con el tema tengo estas dos dudas, en caso de restar dos registros y el resultado sea inferior a cero (número negativo), ¿Qué ocurre con el valor?

Y por otra parte, ¿En caso de multiplicar dos números y el resultado decimal sea mayor a 255 es decir 0xFF para arriba (sea 0x 100, 0x101, 0x102…), como se almacena el número? (Supongo que lo que hace es apelotonar el segundo byte de momento)

* * *​

Ya sabes tío, me encanta que aportes estos temas al foro. Nos servirá a muchos. ¡Un abrazo! :heart:
 

Inferno

Miembro insignia
Miembro insignia
Respuesta: GBA | ASM | Clase Número 3: Instrucciones Básicas

Había visto hace tiempo este tema, pero nunca me había parado a probar las rutinas hasta hoy, incitado por este tema, y estuve mirando y no me funcionaban ninguna de las dos, ni la de cheve ni la de felix, por eso decidí mirar el motivo y el de la de cheve es el siguiente:

Código:
.byte 0x020242D8
.word 0x020242D8
No entendí muy bien porque desde un principio pusiste .byte cuando se trata de una word.
Compilar me compilaba igual, pero a la hora de probar el script no funcionaba.

Código:
.text
.align 2
.thumb
.thumb_func
.global Rutina_1

main:
	push {r0-r1, lr} @Arreglamos el push y el pop
	ldr r0, .PokemonLevel
	ldr r1, .VAR
	ldrb r0, [r0]
	strb r0, [r1]
	pop {r0-r1, pc} 

.align 2

.VAR:                            
	.word 0x020270B6 + (0x800D * 2)
.PokemonLevel:
	.word 0x020242D8

Luego la de felix directamente no compilaba y era por eso también, cambiando el .byte por el .word ya lo hacía, el problema es que a la hora de probarlo tampoco funcionaba. Por tanto decidí hacer yo una adaptación de la rutina y este es el resultado:

Código:
.text
.align 2
.thumb
.thumb_func
.global Rutina_1

main:
	push {r0-r2, lr} 
	ldr r0, .PokemonParty
	ldr r1, .VAR
	ldrb r2, .IncrementoPokemon
        mul r2, r2, r1 
	add r0, r2, #0x54
	ldrb r0, [r0]	
	strb r0, [r1]
	pop {r0-r2, pc} 

.align 2

.VAR:                            
	.word 0x020370D0
.PokemonParty:
	.word 0x02024284
.IncrementoPokemon:
	.byte 0x64
Después de revisar y revisar no entiendo que es lo que está mal, lo que hago es multiplicar el valor que haya en la variable 0x800D por 0x64 para saber de que slot del equipo se trata y luego al resultado de eso le sumo #0x54 para que marque el nivel del Pokémon. Haciendo calculos y comprobándolos serían perfectos. Haciendo la multiplicación sacamos uno de estos datos:
0x02024284 100b Party Pokemon 1
0x020242E8 100b Party Pokemon 2
0x0202434C 100b Party Pokemon 3
0x020243B0 100b Party Pokemon 4
0x02024414 100b Party Pokemon 5
0x02024478 100b Party Pokemon 6
Y por la suma de 0x54 a uno de los offsets anteriores se saca el offset del nivel de ese slot del equipo.
El error que me sale a la hora de compilar es: inmediate value out of range

El script que pretendo utilizar para sacar el valor de 0x800D es este:
Código:
#dynamic 0x800000

#org @start
lockall
special 0x9F
waitstate
copyvar 0x8004 0x800D
compare 0x800D 0x7
if 0x1 goto @cancel
callasm 0x880201
buffernumber 0x0 0x800D
msgbox @a 0x6
releaseall
end

#org @a
= El nivel de este Pokémon es: [buffer1]

#org @cancel
releaseall
end

Ya me estoy volviendo loco, ayuda por favor xDD @Cheve J. @Enamorat de Aaró @Kaiser de Emperana siento molestar '^^

EDIT: Después de fijarme un poco me di cuenta de que el error de compilar podría venir del comando add, y así era, luego de modificar la rutina de esta manera:
Código:
        ...
        mul r2, r2, r1
[COLOR="Red"]        add r2, r2, #0x54
	add r0, r0, r2[/COLOR]
	ldrb r0, [r0]
        ...
Ya compila, pero sigue sin funcionar :hmm:
 
Última edición:

Kaiser de Emperana

Called in hand
Re: Respuesta: GBA | ASM | Clase Número 3: Instrucciones Básicas

Había visto hace tiempo este tema, pero nunca me había parado a probar las rutinas hasta hoy, incitado por este tema, y estuve mirando y no me funcionaban ninguna de las dos, ni la de cheve ni la de felix, por eso decidí mirar el motivo y el de la de cheve es el siguiente:

Código:
.byte 0x020242D8
.word 0x020242D8
No entendí muy bien porque desde un principio pusiste .byte cuando se trata de una word.
Compilar me compilaba igual, pero a la hora de probar el script no funcionaba.

Código:
.text
.align 2
.thumb
.thumb_func
.global Rutina_1

main:
	push {r0-r1, lr} @Arreglamos el push y el pop
	ldr r0, .PokemonLevel
	ldr r1, .VAR
	ldrb r0, [r0]
	strb r0, [r1]
	pop {r0-r1, pc} 

.align 2

.VAR:                            
	.word 0x020270B6 + (0x800D * 2)
.PokemonLevel:
	.word 0x020242D8

Luego la de felix directamente no compilaba y era por eso también, cambiando el .byte por el .word ya lo hacía, el problema es que a la hora de probarlo tampoco funcionaba. Por tanto decidí hacer yo una adaptación de la rutina y este es el resultado:

Código:
.text
.align 2
.thumb
.thumb_func
.global Rutina_1

main:
	push {r0-r1, lr} @Arreglamos el push y el pop
	ldr r0, .PokemonLevel
	ldr r1, .VAR
	ldrb r0, [r0]
	strb r0, [r1]
	pop {r0-r1, pc} 

.align 2

.VAR:                            
	.word 0x020270B6 + (0x800D * 2)
.PokemonLevel:
	.word 0x020242D8
Después de revisar y revisar no entiendo que es lo que está mal, lo que hago es multiplicar el valor que haya en la variable 0x800D por 0x64 para saber de que slot del equipo se trata y luego al resultado de eso le sumo #0x54 para que marque el nivel del Pokémon. Haciendo calculos y comprobándolos serían perfectos. Haciendo la multiplicación sacamos uno de estos datos:


Y por la suma de 0x54 a uno de los offsets anteriores se saca el offset del nivel de ese slot del equipo.
El error que me sale a la hora de compilar es: inmediate value out of range

El script que pretendo utilizar para sacar el valor de 0x800D es este:
Código:
#dynamic 0x800000

#org @start
lockall
special 0x9F
waitstate
copyvar 0x8004 0x800D
compare 0x800D 0x7
if 0x1 goto @cancel
callasm 0x880201
buffernumber 0x0 0x800D
msgbox @a 0x6
releaseall
end

#org @a
= El nivel de este Pokémon es: [buffer1]

#org @cancel
releaseall
end

Ya me estoy volviendo loco, ayuda por favor xDD @Cheve J. @Enamorat de Aaró @Kaiser de Emperana siento molestar '^^

EDIT: Después de fijarme un poco me di cuenta de que el error de compilar podría venir del comando add, y así era, luego de modificar la rutina de esta manera:
Código:
        ...
        mul r2, r2, r1
[COLOR="Red"]        add r2, r2, #0x54
	add r0, r0, r2[/COLOR]
	ldrb r0, [r0]
        ...
Ya compila, pero sigue sin funcionar :hmm:
Bueno, con el edit que pusiste ya se fue uno de los problemas. El otro está en:
Código:
...
ldr r1, .VAR
...
Lo que estás cargando en r1 es el puntero al valor de la variable, no el valor de la variable, así que lo que estás multiplicando termina siendo: 0x020370D0 * 0x64 = 0xc9581140. Que se sale por un poquiiiito de la ram xD
Solo te falta leer el valor almacenado en la dirección:
Código:
...
ldr r1, .VAR
ldrh r1, [r1]
...
Creo que eso sería todo.
Saludos.

EDIT: NO, no bastaba con eso, me saltee el final de la rutina.
Yo la dejaría algo tal que así: (ESTO ESTÁ MAL, VER MI SIGUIENTE MENSAJE)
Código:
.text
.align 2
.thumb
.thumb_func
.global Rutina_1

main: 
	ldr r0, .PokemonParty
	ldr r1, .VAR
	ldrh r3, [r1]
	mov r2, #0x64
	mul r2, r2, r3 
	add r2, r2, #0x54
	add r0, r0, r2
	ldrb r0, [r0]	
	strb r0, [r1]
	bx lr

.align 2

.VAR:                            
	.word 0x020370D0
.PokemonParty:
	.word 0x02024284
Los push de los registros r0 a r3 son innecesarios. Y el push de lr también ya que no llamás a ninguna otra función (si hubieras hecho un bl si lo sería).
 
Última edición:

Lunos

Enfrentando a La Organización
Miembro insignia
Respuesta: Re: Respuesta: GBA | ASM | Clase Número 3: Instrucciones Básicas

Yo la dejaría algo tal que así:
Código:
.text
.align 2
.thumb
.thumb_func
.global Rutina_1

main: 
	ldr r0, .PokemonParty
	ldr r1, .VAR
	ldrh r3, [r1]
	ldrb r2, .IncrementoPokemon
        mul r2, r2, r3 
	add r2, r2, #0x54
	add r0, r0, r2
	ldrb r0, [r0]	
	strb r0, [r1]
	bx lr

.align 2

.VAR:                            
	.word 0x020370D0
.PokemonParty:
	.word 0x02024284
.IncrementoPokemon:
	.byte 0x64
Esto es lo que necesitaba. Yo justamente le pregunté a @FEL!X si podia echarle un vistazo pues el compilador tiraba 2 o 3 errores, pero veo que ya no será necesario. Asi que, esta rutina guarda el nivel de un Pokémon seleccionado por el jugador (por ejemplo, mediante el Special 0x9F) en la variable 0x800D, ¿correcto?
 

Inferno

Miembro insignia
Miembro insignia
Respuesta: GBA | ASM | Clase Número 3: Instrucciones Básicas

Todavía me sigue fallando, no se si ya soy yo o el script o la rutina... xD

(Ponedlo a x2, aunque no hay mucho que ver)



El script que uso es el de ahí arriba.

Si alguien la prueba y me dice si le pasa lo mismo ayudaría.
 

Kaiser de Emperana

Called in hand
Re: Respuesta: GBA | ASM | Clase Número 3: Instrucciones Básicas

Esto es lo que necesitaba. Yo justamente le pregunté a @FEL!X si podia echarle un vistazo pues el compilador tiraba 2 o 3 errores, pero veo que ya no será necesario. Asi que, esta rutina guarda el nivel de un Pokémon seleccionado por el jugador (por ejemplo, mediante el Special 0x9F) en la variable 0x800D, ¿correcto?
Exáctamente, eso hace. Pero con cambiar el 0x54 por otro valor de acá y bueno, la cantidad de bytes que lee, se podrían leer bastantes más datos.

Todavía me sigue fallando, no se si ya soy yo o el script o la rutina... xD

(Ponedlo a x2, aunque no hay mucho que ver)



El script que uso es el de ahí arriba.

Si alguien la prueba y me dice si le pasa lo mismo ayudaría.
Ya edite mi mensaje, había un error en la rutina que se me había pasado.
------------------------
Otro edit más...
Y por esto es que hay probar bien las cosas y no sólo con el caso más sencillo :D
El puntero a la variable 0x8004 estaba mal en la rutina y el script necesitaba unos retoques.
Rutina:
Código:
.text
.align 2
.thumb
.thumb_func
.global Rutina_1

main: 
	ldr r0, .PokemonParty
	ldr r1, .VAR
	ldrh r3, [r1]
	mov r2, #0x64
	mul r2, r2, r3 
	add r2, r2, #0x54
	add r0, r0, r2
	ldrb r0, [r0]	
	strb r0, [r1]
	bx lr

.align 2

.VAR:                            
	.word 0x020370C0
.PokemonParty:
	.word 0x02024284
Script:
Código:
#dynamic 0x800000

#org @start
lockall
special 0x9F
waitstate
compare 0x8004 0x7
if 0x1 goto @cancel
callasm 0x880201
buffernumber 0x0 0x8004
msgbox @a 0x6
releaseall
end

#org @a
= El nivel de este Pokémon es: [buffer1]

#org @cancel
releaseall
end
Ya la probé bien, esta vez no debería de haber errores...
 
Última edición:

Berserker1523

2-Intentando discernir qué es lo más importante...
Respuesta: GBA | ASM | Clase Número 3: Instrucciones Básicas

Mi rutina:

Código:
.text
.align 2
.thumb
.thumb_func
.global Rutina_1

main:
@Esto es un comentario, algo que no será léido al compilar pero me sirve para explicar el código que hice
@para leerlo en un futuro y entenderlo o por si alguien más lo lee lo pueda entender
	@pongo en la pila los registros r0, r1, r2 y el lr, que contiene la forma de volver
	@a la línea del programa desde donde se llamó a esta rutina
	push {r0-r2, lr}
	
	@cargo en r0 el valor que tiene esta etiqueta
	ldr r0, .FirstPokemonLevel
	
	@cargo en r0 el valor que tiene esta etiqueta
	ldr r1, .VAR8004 
	
	@cargo en r1 el byte al que apunta el valor anterior de r1 en memoria
	@es decir busco en memoria que valor está en la dirección 0x020242D8
	@y se lo asigno a r1.
	@Lo que no explicó cheve es que [] significa acceder a memoria
	ldrb r1, [r1]

	@el registro r2 ahora tiene el valor 100 decimal
	ldr r2, =(100)
	
	@multiplico r1 con r2, ya que usaré el mismo script de los mensajes de arriba con el special 0x9F
	@en r1 habra un valor entre 0 y 5 que es el numero del pokemon
	@que elegi con el scpecial 0x9F y como los datos de cada pokemon ocupan 100 bytes,
	@multiplicando por este valor y sumando con r0 como haré ahora
	@obtendré el nivel del pokemon que escogí
	mul r1, r2

	@ahora r0 contiene la dirección en memoria que contiene el nivel del pokemon
	@que escogí con el special en el script
	add r0, r1 
	
	@cargo en r0 el byte al que apuntaba la direccion que tenia r0 en memoria
	ldrb r0, [r0]
	ldr r2, .VAR8004
	
	@el valor de la variable 8004 que esta en memoria ahora tiene el valor que calculé con todo este rollo
	str r0, [r2]
	
	@saco los registros r0, r1, r2 y pc para restaurar la pila, ahora pc tiene el valor
	@que tenia lr al hacer push, por lo cual el programa avanzará a la siguiente 
	@linea despues del callasm del script
	pop {r0-r2, pc}

.align 2

.VAR8004:                            
	.word 0x020370C0
	
.FirstPokemonLevel:
	.word 0x020242D8
 
Última edición:
Arriba