• Just a reminder that providing specifics on, sharing links to, or naming websites where ROMs can be accessed is against the rules. If your post has any of this information it will be removed.
  • Ever thought it'd be cool to have your art, writing, or challenge runs featured on PokéCommunity? Click here for info - we'd love to spotlight your work!
  • Our weekly protagonist poll is now up! Vote for your favorite Trading Card Game 2 protagonist in the poll by clicking here.
  • Welcome to PokéCommunity! Register now and join one of the best fan communities on the 'net to talk Pokémon and more! We are not affiliated with The Pokémon Company or Nintendo.

Help Thread: ASM & Disassembly

Status
Not open for further replies.
I think the simplest way would be like this:
Code:
mov r0, numerator
mov r1, denominator
mov r2, #100
mul r0, r2
lsr r2, r1, #1
add r0, r2
swi #6
What it does is it multiplies the numerator by 100 so the result is a percentage, then adds half of the denominator to make sure the result is correctly rounded (no need to process the remainder), and then divides. I haven't tested this code, but I'm pretty sure it works.

In a case like:
Numerator = 35
Denomenator = 102
-
you'd do, swi(3551, 102)
which is 34, and the modulo return is 83.

The expected return would be 35. I don't think you can get away with not checking the remainder. You could multiply by 1000 at the start, then you can shed the last digit if it's less than 5, but that's not faster, since swi does the modulo itself.
 
In a case like:
Numerator = 35
Denomenator = 102
-
you'd do, swi(3551, 102)
which is 34, and the modulo return is 83.

The expected return would be 35. I don't think you can get away with not checking the remainder. You could multiply by 1000 at the start, then you can shed the last digit if it's less than 5, but that's not faster, since swi does the modulo itself.
When I divide 35 by 102, the result is roughly 0.343137, so I'd say 34 would be right here. The idea behind adding half of the denominator before dividing is that you essentially increase the quotient by 0.5, and then the decimal places get cut off. So if the digit after the point is 5 or higher, you'll reach a new integer, thus it rounds correctly.

You can also do it the way you suggested, but I'd multiply by 100 at the start and add 1 in case you need to round up. Also, you need to compare the full remainder with half of the denominator, not half of the remainder.
 
When I divide 35 by 102, the result is roughly 0.343137, so I'd say 34 would be right here. The idea behind adding half of the denominator before dividing is that you essentially increase the quotient by 0.5, and then the decimal places get cut off. So if the digit after the point is 5 or higher, you'll reach a new integer, thus it rounds correctly.

You can also do it the way you suggested, but I'd multiply by 100 at the start and add 1 in case you need to round up. Also, you need to compare the full remainder with half of the denominator, not half of the remainder.
Oh, that's quite nice. I hadn't thought of doing things like that, very nicely done. My only suggestion is that you use div instead of SWI if you're not using the modulo div component (pretty sure it's faster).
 
Thanks for the help everyone! I think the lesson of today is that I have poor intuition when it comes to simple math V_V I thought the computation would have been significantly more complicated than either of the provided routines...
 
Yeah, you don't need to do all of that. Just uncompress the Pokemon, and copy it into the opponent's party space. What I've been trying to say is that the opponent's party is purged before battling, so inorder for your storage pokemon which you've copied over to not be purged, you'd need to hook to turn off the purging mechanic. :)

OK I sorta kinda feel stupid, I was miss understanding why you were telling me to hook. Anyways I hooked rewrote the routine to copy the data from the players current party, and simply calling the swap party storage routine at the beginning and end of the routine(to avoid having to recalc stats) which ended up working, BUT the enemy's HP, level and such were seemingly cleared no matter what I did. So, I rewrote it again, this time just straight up taking the 0x50 bytes that the pokemon are stored as, recalced the stats,(while they're in the opponents party, which is probably why it doesnt work). Now this still "worked" in a sense, but the game started endlessly recreating the trainers party, which ended up a black screen.

Heres the current form of the routine:
(Fbi I hooked into the same place that you did for your frontier party gen routine)
Spoiler:
 
Heres the current form of the routine:
(Fbi I hooked into the same place that you did for your frontier party gen routine)
Spoiler:

Do you happen to have the hook location's address? The code doesn't make it very obvious, unfortunately.


Code:
.text
.align 2
.thumb
.thumb_func

Main:
	push {r0-r6}
	[B]ldr r0, =(0x205) @doing this is perfectly fine too[/B]
	ldr r3, =(0x806E6D0 +1)
	bl linker
	cmp r0, #0x0
	beq end
	ldr r5, =(0x2024284) @change this to storage location if u wish
	mov r6, #0x0

Loop:
	cmp r6, #0x6
	beq end
	mov r0, r5
	mov r1, #0x64 @size, compressed should be 0x50. Party-swap I made will uncompress them when swapping though.
	mul r1, r1, r2
	add r0, r0, r1 @pokemon to copy
	mov r4, r0
	ldr r3, =(0x803E47C +1)
	bl linker
	ldr r4, =(0x202402C) 
	add r1, r1, r4 @place to put copied mon
	@ here you should call memcpy, check IDA for offsets
	add r6, r6, #0x1
	b loop

end:
	@end, return to hooked section, and restore overwritten instructions

linker:
	bx r3
.align 2

A few big errors, I saw were "bl loop". You should just use "b". Another thing was loading byte by byte, that's no good. Consider if the opponent had 6 Pokemon, that's 600 iterations in your loop, slow stuff.
 
Do you happen to have the hook location's address? The code doesn't make it very obvious, unfortunately.


Spoiler:

A few big errors, I saw were "bl loop". You should just use "b". Another thing was loading byte by byte, that's no good. Consider if the opponent had 6 Pokemon, that's 600 iterations in your loop, slow stuff.
Hook location is 0x112F8,
Heres the changed routine via your suggestions:
Code:
.text
.align 2
.thumb
.thumb_func

Main:
	push {r0-r6}
ldr r0, =(0x205) @doing this is perfectly fine too
	ldr r3, =(0x806E6D0 +1)
	bl linker
	cmp r0, #0x0
	beq end
	ldr r5, =(0x203C000) @changed to storage
	mov r6, #0x0

Loop:
	cmp r6, #0x6
	beq end
	mov r0, r5
	mov r1, #0x50 @changed to compensate for the storage
	mul r1, r1, r2
	add r0, r0, r1 @pokemon to copy
	mov r4, r0
	ldr r3, =(0x803E47C +1)
	bl linker
	ldr r4, =(0x202402C) 
	add r1, r1, r4 @place to put copied mon
	ldr r3, =(0x81e5e78 +1) @memcpy as you requested
	bl linker
	add r6, r6, #0x1
	b loop

end: @ending stuff from hook
	pop {r0-r6}
	ldr r0, =(0x400)
	cmp r1, r0
	bne place
	mov r0, #0x0
	ldr r3, =(0x80116AC +1)
	bx r3
	
place:
	ldr r3, =(0x8011304 +1)
	bx r3
linker:
	bx r3
.align 2

And still black screen
 
Commented.

Code:
.text
.align 2
.thumb
.thumb_func

Main:
	push {r0-r6}
ldr r0, =(0x205) @doing this is perfectly fine too
	ldr r3, =(0x806E6D0 +1) @flag check
	bl linker
	cmp r0, #0x0
	beq end
	ldr r5, =(0x203C000) @changed to storage
	mov r6, #0x0

Loop:
	cmp r6, #0x6
	beq end
	mov r0, r5 @storage offset
	mov r1, #0x50 @[b]changed to compensate for the storage[/b]
	mul r1, r1, r2 @[b]what is r2? is this not meant to be mul r1, r1, r6?[/b]
	add r0, r0, r1 @pokemon to copy
	mov r4, r0
	ldr r3, =(0x803E47C +1) @calc effective stats
@[b]won't this overwrite the first 20 bytes of the next pokemon?[/b]
	bl linker
	ldr r4, =(0x202402C) 
	add r1, r1, r4 @place to put copied mon
@[b]r1 will NOT be the same as it was before bl linker[/b]
	ldr r3, =(0x81e5e78 +1) @memcpy as you requested
	bl linker
	add r6, r6, #0x1
	b loop

end: @ending stuff from hook
	pop {r0-r6}
	ldr r0, =(0x400)
	cmp r1, r0
	bne place
	mov r0, #0x0
	ldr r3, =(0x80116AC +1)
	bx r3
	
place:
	ldr r3, =(0x8011304 +1)
	bx r3 @[b]this instruction is unnecessary[/b]
linker:
	bx r3
.align 2
 
Aw, some of this was my fault. I copied his code, and changed to a higher register to save the data, but things like mul I forgot to change back to the high register. Also if you did Party swap Joexv, you don't actually need to recalculate the stats, since I'm 95% sure it is recalculated there. Sorry for the confusion folks :D

Something to add to what Azurile has said, is "b loop" and "Loop:" depending on the compiler this is case sensitive.
 
Aw, some of this was my fault. I copied his code, and changed to a higher register to save the data, but things like mul I forgot to change back to the high register. Also if you did Party swap Joexv, you don't actually need to recalculate the stats, since I'm 95% sure it is recalculated there. Sorry for the confusion folks :D

Something to add to what Azurile has said, is "b loop" and "Loop:" depending on the compiler this is case sensitive.
 
Aw, some of this was my fault. I copied his code, and changed to a higher register to save the data, but things like mul I forgot to change back to the high register. Also if you did Party swap Joexv, you don't actually need to recalculate the stats, since I'm 95% sure it is recalculated there. Sorry for the confusion folks :D

Something to add to what Azurile has said, is "b loop" and "Loop:" depending on the compiler this is case sensitive.

Yea no worries I fixed them, but still nothing. One thing though, is that even is I just take a party pokemon(all stats and everything) it will zero it out, calling the stat recalc, does indeed bring new stats to the pokemon, but it causes a black screen. Which I feel like the original method I was using to try and create the party, by decrypting and all, is by far the easiest way to do this without massive amounts of changes to the existing trainer battle routines.(or just lots of hooks). So I'm gonna rewrite the initial code(again), and see what happens this time.

EDIT: Ok I rewrote the original routine, but it fails to store any pokemon past the first slot of the enemy trainer, it doesnt store moves. Seriously wtf am I doing wrong????
Spoiler:
 
Last edited:
Yea no worries I fixed them, but still nothing. One thing though, is that even is I just take a party pokemon(all stats and everything) it will zero it out, calling the stat recalc, does indeed bring new stats to the pokemon, but it causes a black screen. Which I feel like the original method I was using to try and create the party, by decrypting and all, is by far the easiest way to do this without massive amounts of changes to the existing trainer battle routines.(or just lots of hooks). So I'm gonna rewrite the initial code(again), and see what happens this time.

EDIT: Ok I rewrote the original routine, but it fails to store any pokemon past the first slot of the enemy trainer, it doesnt store moves. Seriously wtf am I doing wrong????
Code:
Push {r0-r7, lr}
.....
pop {r0-r7}
Also I'm not sure whether or not you've completely scrapped it, but in your previous code where I mentioned that r1 will not be the same as it was prior to the bl? I should have also said the same for r0, Furthermore, I believe memcpy requires an argument in r2 of the size you're copying.

It may be a good idea to test using vba-sdl-h. I use it when I can't get routines to work. It can get difficult to stare at your routines for hours and the answer is often as facepalm-y as a misaligned stack.
 
Code:
Push {r0-r7, lr}
.....
pop {r0-r7}
Also I'm not sure whether or not you've completely scrapped it, but in your previous code where I mentioned that r1 will not be the same as it was prior to the bl? I should have also said the same for r0, Furthermore, I believe memcpy requires an argument in r2 of the size you're copying.

It may be a good idea to test using vba-sdl-h. I use it when I can't get routines to work. It can get difficult to stare at your routines for hours and the answer is often as facepalm-y as a misaligned stack.
Well while not as simple as a misaligned stack, a lot of the issues I was having was caused by the RAM offset I was using. Swapped to 0x0203E000 and now the only issue I have is routine based and probably wont be too hard to fix.
Thanks for the help!
 
Quick question.
Touched's ASM Tutorial said:
If we have not pushed LR, we can return with the following code,

bx lr

I'm having problems finding the definition of return as used in this context. Anyone able to clarify?
 
Quick question.
I'm having problems finding the definition of return as used in this context. Anyone able to clarify?

It's the same as a return statement. When you call a subroutine, the value of PC gets set to the location of called subroutine. This gets executed, but when it reaches the end, it needs to start executing the calling subroutine where it left off. This place would be known as the return location. The verb "return" means handing control back to the calling subroutine. When using the BL instruction, LR (the return address) is set, allowing the subroutine to return by setting PC (the address to execute) to that value somehow. This can take the form of BX LR (if LR was unchanged in the course of the routine), MOV PC, LR (if the calling routine uses the same instruction set as the caller), POP {PC} (if the return address was pushed to the stack), etc.
 
This is for a Ruby ROM... And this is part of the ASM code...
Code:
LDR R0, = 0x0202E8C4
LDRH R0, [R0]
CMP R0, #1
BNE FINE
I wanna ask a question about it. Where in this code is it using variable 0x8000 and how can I change it to use variable 0x4015 instead? Thanks~

Inside the spoiler is the entire ASM code, created by Andrea~

Spoiler:
 
This is for a Ruby ROM... And this is part of the ASM code...
Code:
LDR R0, = 0x0202E8C4
LDRH R0, [R0]
CMP R0, #1
BNE FINE
I wanna ask a question about it. Where in this code is it using variable 0x8000 and how can I change it to use variable 0x4015 instead? Thanks~
No clue on the ram map of ruby (not even the rom map, tbh). But assuming that code is correct, the only logical place would be the 0x0202E8C4. I think that because ruby doesn't use DMA***, you can simply access the variable address directly. Do you have a ram map for ruby? You literally just replace that address with the offset for var 0x4015.

***citation needed
 
Hi, I recently started learning ASM and I've got several questions on the basis and on some already written codes. Thank you in advance for your answers.
1) Push and Pop are used not to overwrite the current value of registers, right? So when I'm pushing a register it's like I'm doing a backup of its content while when I'm popping I'm taking back that content from the stack. Since the stack is a LIFO structure, why do we still write this?
push {r0-r2, lr}
[...]
pop{r0-r2, pc}
Does the machine automatically read pop's bracket in reverse order? (So it first pops PC, whose content becomes that of LR, then r2, r1, r0?)

2) I read register r0-r3 don't need to be pushed, is it correct? And why? Is it because they don't contain previous data?

3) I don't understand what "bl" and "bx" commands actually do. "Bl" is a branch with link, so it jumps to a label but first saves in LR the current address? And what about bx? What does the register after bx mean?
I found this code in FBI's tutorial:
main:
push {r0-r2, lr}
@derive 0x828 in register r0
mov r0, #0xFF
lsl r0, r0, #0x3
add r0, r0, #0x30
@this is how we call the function
ldr r1, =(0x806E6D0 +1)
bl linker
@check if set or not
cmp r0, #0x1
beq set
pop {r0-r2, pc}

set:
@if we get here it's set

linker:
bx r1

It loads in r1 the offset of a function, then it uses bl/bx commands. What is it doing here and why?

4)Variables are stored in certain offsets but what about flags? In FBI's tutorial this code is written:
main:
push {r0-r1, lr}

@set r0 and r1 to some values
mov r0, #0xFF
mov r1, #0x8

@multiply r0, and r1 (0xFF * 0x8) = 0x7F8
mul r0, r0, r1

@add 0x30 to 0x7F8 to get 0x828
add r0, r0, #0x30
pop {r0-r1, pc}

So differently from variables, we just use the number of the flag? Is it because flag 0x828 actually is at 0x08000828 offset?

I'm still learning but these are my questions this far (well I guess there are already too many of them)

Again, thank you!
 
Hi, I recently started learning ASM and I've got several questions on the basis and on some already written codes. Thank you in advance for your answers.
1) Push and Pop are used not to overwrite the current value of registers, right? So when I'm pushing a register it's like I'm doing a backup of its content while when I'm popping I'm taking back that content from the stack. Since the stack is a LIFO structure, why do we still write this?

Does the machine automatically read pop's bracket in reverse order? (So it first pops PC, whose content becomes that of LR, then r2, r1, r0?)

The syntax is for convenience. Push places stuff on the stack in descending order (ordered by register number). pop takes it off in ascending order. This has the effect of making the registers stored in numerical order with the smallest register occupying the lowest address (remember the stack is descending, with smaller addresses indicating a larger stack). [Source]

2) I read register r0-r3 don't need to be pushed, is it correct? And why? Is it because they don't contain previous data?

r0-r3 are scratch registers. This is defined in the ARM calling convention. Essentially when calling a function, you just assume they're going to be messed up. Since all the code in a given program makes the same assumption, it is safe to edit them without restoring them to their previous values when your function returns.

3) I don't understand what "bl" and "bx" commands actually do. "Bl" is a branch with link, so it jumps to a label but first saves in LR the current address? And what about bx? What does the register after bx mean?
I found this code in FBI's tutorial:

It loads in r1 the offset of a function, then it uses bl/bx commands. What is it doing here and why?

I explained BL to someone else recently . This might help you since they had similar questions. TL;DR BL sets the Link Register and is used to call functions. BX branches to the address held in the register operand. It is used to switch between ARM and THUMB modes, but it has other uses such as calling functions that you don't know the address of (from a table of functions or something) and bypassing branch distance restrictions in BL.

4)Variables are stored in certain offsets but what about flags? In FBI's tutorial this code is written:

So differently from variables, we just use the number of the flag? Is it because flag 0x828 actually is at 0x08000828 offset?

I'm still learning but these are my questions this far (well I guess there are already too many of them)

Again, thank you!

Some variables (0x800X) are stored at specific RAM offsets. The others are stored in a block of memory that overlaps with flags. If you wish to get the address of a variable such as 0x4000, or access a flag, you should use the engine functions to do this. They are the same functions used by setvar, addvar, checkflag, setflag, etc.

The code that FBI provides there is something that calls a function that checks whether a flag is set. It is the same function that is used by the checkflag script command. This function takes a flag index in r0 and puts (returns) a 1 in r0 if the flag is set, otherwise it returns 0. This function will determine the address of the flag for you and perform the relevant calculations.

The flag is not at address 0x08000828. This would be a ROM address so that wouldn't make sense anyway as flags can change (they'd need to be in the RAM).
 
Thank you very much! :)
I'd just need some clarifications: everytime I call a function, I have to load it into rX register, then use "bl *label*" and put "bx rX" in that label? The function is executed after that last line, correct? And does it automatically put the value stored in LR into PC at the end of the function?
About flags, they all can be accessed by 0xXXX then?
Sorry for bothering.

EDIT
I found these lines in a code
ldr r1, =(0x806D600 +1)
bx r1

In this case, after executing the function it all ends because I haven't stored PC (or LR?) with bl?
 
Status
Not open for further replies.
Back
Top