• Our software update is now concluded. You will need to reset your password to log in. In order to do this, you will have to click "Log in" in the top right corner and then "Forgot your password?".
  • 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.

Joexv

ManMadeOfGouda joexv.github.io
  • 1,037
    Posts
    11
    Years
    OK so I'm trying to make a routine that takes a pokemon thats stored in FBI's storage routine(which is determined by the value in var 0x8000) then store it into a trainers party setup in RAM(which trainer slot determined by var 0x8001)
    the EV for the transferred Pokemon is set by var 0x8002. Now I have 2 versions of the routine, the first works, but is very messy/has poor execution, in which it will only store the first Pokemon.

    The second routine has been rewritten a few times, each time with different results, none good. Currently it crashes the ROM, previously it just froze.

    Working old routine:
    Spoiler:

    Broken new routine:
    Spoiler:

    Any help is appreciated!
     
  • 417
    Posts
    9
    Years
    • Seen Nov 20, 2016
    OK so I'm trying to make a routine that takes a pokemon thats stored in FBI's storage routine(which is determined by the value in var 0x8000) then store it into a trainers party setup in RAM(which trainer slot determined by var 0x8001)
    the EV for the transferred Pokemon is set by var 0x8002. Now I have 2 versions of the routine, the first works, but is very messy/has poor execution, in which it will only store the first Pokemon.

    The second routine has been rewritten a few times, each time with different results, none good. Currently it crashes the ROM, previously it just froze.

    Working old routine:
    Spoiler:

    Broken new routine:
    Spoiler:

    Any help is appreciated!
    I'm not too familiar with the storage routine, so I'm not entirely sure what you're trying to do. Anyways, a few things popped out when I scanned what you wrote.

    I'm surprised the first routine even worked because you have
    Code:
    Decrypt:
    ldr r2, =(0x803FBE8)
    bx r2
    That should be executing 0x0803FBE8 as ARM, which I doubt you want. And also, after each of the decrypts, you have strh r0, [r2, imm]. But r2 should have been messed up by the get_attr. The offset you're storing the decrypted data to should be held in a register above r3, or at the very least re-derived after the bl. As a side note, the .align 2 should come before the literal pool. The entire reason it exists is because the .VAR and .Var_8004 needs to be word aligned.

    You make a similar assumption in the second routine. You appear to assume that r3 remains unchanged during get_attr. So the second time you "bl Linker," you are almost definitely bx'ing to an address that you should not. That seems to be your main issue in both routines. You should assume that r1-r3 (and r0 if there is no return) are rubbish after bl'ing to anything. This also means you shouldn't have to push r0-r3 at the beginning unless there's something specific you're saving.

    I just noticed something else. You have
    Code:
    ldr r7, =(0x2037102)
    strb r0, [r7]
    .....
    ldr r7, =(0x2037104)
    strh r0, [r7]
    .....
    ldr r7, =(0x2037106)
    strh r0, [r7]
    .....
    ldr r7, =(0x2037108)
    strh r0, [r7]
    .....
    ldr r7, =(0x203710A)
    strh r0, [r7]
    .....
    ldr r7, =(0x203710C)
    strh r0, [r7]
    .....
    ldr r7, =(0x203710E)
    strh r0, [r7]
    When you could instead be using
    Code:
    strb r0, [r7, #0x0]
    .....
    strh r0, [r7, #0x2]
    .....
    strh r0, [r7, #0x4]
    .....
    strh r0, [r7, #0x6]
    .....
    strh r0, [r7, #0x8]
    etc
     
    Last edited:

    Touched

    Resident ASMAGICIAN
  • 625
    Posts
    9
    Years
    • Age 122
    • Seen Feb 1, 2018
    OK so I'm trying to make a routine that takes a pokemon thats stored in FBI's storage routine(which is determined by the value in var 0x8000) then store it into a trainers party setup in RAM(which trainer slot determined by var 0x8001)
    the EV for the transferred Pokemon is set by var 0x8002. Now I have 2 versions of the routine, the first works, but is very messy/has poor execution, in which it will only store the first Pokemon.

    The second routine has been rewritten a few times, each time with different results, none good. Currently it crashes the ROM, previously it just froze.

    Are you sure you haven't mixed up which is working and which is not? The one you've labelled working branches to a THUMB routine in ARM mode which should crash. I don't see anything wrong with the second routine besides some needless code repetition. But I'm not familiar with the addresses being used, so I'm not too sure.

    EDIT: Ninja
     
    Last edited:
  • 218
    Posts
    10
    Years
    • Seen Nov 12, 2021
    OK so I'm trying to make a routine that takes a pokemon thats stored in FBI's storage routine(which is determined by the value in var 0x8000) then store it into a trainers party setup in RAM(which trainer slot determined by var 0x8001)
    the EV for the transferred Pokemon is set by var 0x8002. Now I have 2 versions of the routine, the first works, but is very messy/has poor execution, in which it will only store the first Pokemon.

    The second routine has been rewritten a few times, each time with different results, none good. Currently it crashes the ROM, previously it just froze.

    Working old routine:
    Spoiler:

    Broken new routine:
    Spoiler:

    Any help is appreciated!


    Well, you don't even have to use set_attr or get_attr if you use this, it's much more convenient to edit pokemon data.
     

    Blah

    Free supporter
  • 1,924
    Posts
    11
    Years
    OK so I'm trying to make a routine that takes a pokemon thats stored in FBI's storage routine(which is determined by the value in var 0x8000) then store it into a trainers party setup in RAM(which trainer slot determined by var 0x8001)
    the EV for the transferred Pokemon is set by var 0x8002. Now I have 2 versions of the routine, the first works, but is very messy/has poor execution, in which it will only store the first Pokemon.

    The second routine has been rewritten a few times, each time with different results, none good. Currently it crashes the ROM, previously it just froze.

    Any help is appreciated!

    If I'm understanding correctly, you're trying to take a stored Pokemon and add it to the party? In which case, "compressed" Pokemon don't need to have their EVs reset or stored. Pokemon compression takes the first 0x50 bytes of the 0x64 Pokemon data structure (the rest is calculated upon uncompression, hence why you'll notice putting a Pokemon into the PC and withdrawing it resets its HP/status).

    Anyways, there's a few problems you need to consider before doing something.
    1) If pokemon you take from storage is not the last one, storage Pokemon after it need to be moved up to utilise empty slots later on.
    2) If party already has 6 pkmn, how will you handle it?

    there's a lot of edge cases when it comes to Pokemon storage, anyways, I suggest you use memcpy. Also the need to pass a slot ID for the party isn't needed because if it's not-full we can just place it in the next available slot.

    You should just use a memcpy/swi like this:


    Code:
    ldr r0, =(0x2024029)
    ldr r1, =(0x2024284)
    ldrb r0, [r0]
    mov r2, #0x64
    mul r0, r0, r2
    add r0, r0, r1 @dest
    ldr r1, =(0x203C000)
    ldr r2, =(0x20370B8)
    ldrh r2, [r2]
    mov r3, #0x50
    mul r2, r2, r3
    add r1, r1, r2 @src
    mov r2, #0x50 @size
    
    swi 0xC @alternatively you can use memcpy

    Well, you don't even have to use set_attr or get_attr if you use this, it's much more convenient to edit pokemon data.

    You lose portability to ROMs without this implemented. Also, the code isn't more simplified length-wise since now you need to do bit-wise operations for certain accesses (though it's simplified execution wise).
     

    Joexv

    ManMadeOfGouda joexv.github.io
  • 1,037
    Posts
    11
    Years
    I'm not too familiar with the storage routine, so I'm not entirely sure what you're trying to do. Anyways, a few things popped out when I scanned what you wrote.

    I'm surprised the first routine even worked because you have
    Code:
    Decrypt:
    ldr r2, =(0x803FBE8)
    bx r2
    That should be executing 0x0803FBE8 as ARM, which I doubt you want. And also, after each of the decrypts, you have strh r0, [r2, imm]. But r2 should have been messed up by the get_attr. The offset you're storing the decrypted data to should be held in a register above r3, or at the very least re-derived after the bl. As a side note, the .align 2 should come before the literal pool. The entire reason it exists is because the .VAR and .Var_8004 needs to be word aligned.

    You make a similar assumption in the second routine. You appear to assume that r3 remains unchanged during get_attr. So the second time you "bl Linker," you are almost definitely bx'ing to an address that you should not. That seems to be your main issue in both routines. You should assume that r1-r3 (and r0 if there is no return) are rubbish after bl'ing to anything. This also means you shouldn't have to push r0-r3 at the beginning unless there's something specific you're saving.

    I just noticed something else. You have
    Code:
    ldr r7, =(0x2037102)
    strb r0, [r7]
    .....
    ldr r7, =(0x2037104)
    strh r0, [r7]
    .....
    ldr r7, =(0x2037106)
    strh r0, [r7]
    .....
    ldr r7, =(0x2037108)
    strh r0, [r7]
    .....
    ldr r7, =(0x203710A)
    strh r0, [r7]
    .....
    ldr r7, =(0x203710C)
    strh r0, [r7]
    .....
    ldr r7, =(0x203710E)
    strh r0, [r7]
    When you could instead be using
    Code:
    strb r0, [r7, #0x0]
    .....
    strh r0, [r7, #0x2]
    .....
    strh r0, [r7, #0x4]
    .....
    strh r0, [r7, #0x6]
    .....
    strh r0, [r7, #0x8]
    etc
    Ok Ill see if I cant fix it with those suggestions. In regards to the strh r0, [r7, #0x2], I originally had it like that, but was just messing around seeing if that was what was causing any of my issues.
    Are you sure you haven't mixed up which is working and which is not? The one you've labelled working branches to a THUMB routine in ARM mode which should crash. I don't see anything wrong with the second routine besides some needless code repetition. But I'm not familiar with the addresses being used, so I'm not too sure.

    EDIT: Ninja
    I hope not

    Well, you don't even have to use set_attr or get_attr if you use this, it's much more convenient to edit pokemon data.
    I sorta kinda forgot about that, but I'll leave it as is just cause that's what I know.(ish)

    If I'm understanding correctly, you're trying to take a stored Pokemon and add it to the party? In which case, "compressed" Pokemon don't need to have their EVs reset or stored. Pokemon compression takes the first 0x50 bytes of the 0x64 Pokemon data structure (the rest is calculated upon uncompression, hence why you'll notice putting a Pokemon into the PC and withdrawing it resets its HP/status).

    Anyways, there's a few problems you need to consider before doing something.
    1) If pokemon you take from storage is not the last one, storage Pokemon after it need to be moved up to utilise empty slots later on.
    2) If party already has 6 pkmn, how will you handle it?

    there's a lot of edge cases when it comes to Pokemon storage, anyways, I suggest you use memcpy. Also the need to pass a slot ID for the party isn't needed because if it's not-full we can just place it in the next available slot.

    You should just use a memcpy/swi like this:


    Code:
    ldr r0, =(0x2024029)
    ldr r1, =(0x2024284)
    ldrb r0, [r0]
    mov r2, #0x64
    mul r0, r0, r2
    add r0, r0, r1 @dest
    ldr r1, =(0x203C000)
    ldr r2, =(0x20370B8)
    ldrh r2, [r2]
    mov r3, #0x50
    mul r2, r2, r3
    add r1, r1, r2 @src
    mov r2, #0x50 @size
    
    swi 0xC @alternatively you can use memcpy
    No what I'm tryiong to do is take the stored pokemon and turn it into an enemy trainers party Pokemon, not removing anything from the storage or the players party.
     
    Last edited:

    Blah

    Free supporter
  • 1,924
    Posts
    11
    Years
    Ok Ill see if I cant fix it with those suggestions. In regards to the strh r0, [r7, #0x2], I originally had it like that, but was just messing around seeing if that was what was causing any of my issues.

    I hope not


    I sorta kinda forgot about that, but I'll leave it as is just cause that's what I know.(ish)


    No what I'm tryiong to do is take the stored pokemon and turn it into an enemy trainers party Pokemon, not removing anything from the storage or the players party.

    Err, that's going to take a hook, just as an aside. Also, use the snippet I posted but change 0x2024284 into the opponent's party, it should still work. The hook will have to remove "Opponent party purge" or whatever it's called.
     

    Joexv

    ManMadeOfGouda joexv.github.io
  • 1,037
    Posts
    11
    Years
    Err, that's going to take a hook, just as an aside. Also, use the snippet I posted but change 0x2024284 into the opponent's party, it should still work. The hook will have to remove "Opponent party purge" or whatever it's called.

    Why would it need a hook?
     

    Blah

    Free supporter
  • 1,924
    Posts
    11
    Years
    Why would it need a hook?

    I assume you're copying this data over to opponent party because you want to battle an opponent with that party later on? Well, generally, before a battle happens, during the setup the opponent's Party is purged. You'd need to remove this purge based on condition, hence the hook.
     

    Joexv

    ManMadeOfGouda joexv.github.io
  • 1,037
    Posts
    11
    Years
    I assume you're copying this data over to opponent party because you want to battle an opponent with that party later on? Well, generally, before a battle happens, during the setup the opponent's Party is purged. You'd need to remove this purge based on condition, hence the hook.

    The party is strictly in RAM, that way its not purged.
     

    Blah

    Free supporter
  • 1,924
    Posts
    11
    Years
    The party is strictly in RAM, that way its not purged.

    The opponent's party is purged before each battle via 0803DA34. It's because it's in the RAM which allows it to be purged, ofc, the copy you'd have in 0203C000 will not be purged. Anyways, if it was your plan to have the player battle a stored Pokemon, then a hook would be necessary.
     

    Joexv

    ManMadeOfGouda joexv.github.io
  • 1,037
    Posts
    11
    Years
    The opponent's party is purged before each battle via 0803DA34. It's because it's in the RAM which allows it to be purged, ofc, the copy you'd have in 0203C000 will not be purged. Anyways, if it was your plan to have the player battle a stored Pokemon, then a hook would be necessary.

    Opps sorry i miss worded that. What i meant was the data that the game reads to determine the party is stored in ram instead of the Rom. Butafter some tweaking the issue persists and the game is reset upon calling the routine.
     

    Blah

    Free supporter
  • 1,924
    Posts
    11
    Years
    Opps sorry i miss worded that. What i meant was the data that the game reads to determine the party is stored in ram instead of the Rom. Butafter some tweaking the issue persists and the game is reset upon calling the routine.

    Perhaps it was I who was being unclear. First, can I confirm that you are trying to make the player battle 1 or more pokemon from the storage?

    If that's not the case, then the routine I posted in an earlier post is the solution. Also,
    What i meant was the data that the game reads to determine the party is stored in ram instead of the Rom.
    I was talking about the opponent party, since that (unlike the player party) is not stored in the sav datastructure, and thus will not be derived on reset. The opponent's party is purged every time you do battle as well.
     

    Joexv

    ManMadeOfGouda joexv.github.io
  • 1,037
    Posts
    11
    Years
    Perhaps it was I who was being unclear. First, can I confirm that you are trying to make the player battle 1 or more pokemon from the storage?

    If that's not the case, then the routine I posted in an earlier post is the solution. Also,
    Yes I'm trying to make the player battle pokemon from the storage. The routine is simply meant to take the species, level, and moves from the stored pokemon and store them in RAM to be used as a trainer's party.(plus evs set by a var)

    I was talking about the opponent party, since that (unlike the player party) is not stored in the sav datastructure, and thus will not be derived on reset. The opponent's party is purged every time you do battle as well.

    Yea I understand that.
     
  • 417
    Posts
    9
    Years
    • Seen Nov 20, 2016
    Yes I'm trying to make the player battle pokemon from the storage. The routine is simply meant to take the species, level, and moves from the stored pokemon and store them in RAM to be used as a trainer's party.(plus evs set by a var)
    I don't think I quite understand why you need to use an intermediate step of storing those things in a specific ram location, but maybe I'm just terrible at understanding. Regardless, going from an offset of an encrypted pokemon and storing the unencrypted data in a specific location is simple enough, so perhaps you can post your modified routines for us to see?

    MY question: could someone describe simplest way to go from numerator and denominator to a percentage? I found "Div," but I'm not sure how to utilize what "Supervisor Mode " 6 does. I specifically would like a rounded percentage as an integer, not the number of times the numerator goes into the denominator/ignoring remainder.
     

    Blah

    Free supporter
  • 1,924
    Posts
    11
    Years
    Yes I'm trying to make the player battle pokemon from the storage. The routine is simply meant to take the species, level, and moves from the stored pokemon and store them in RAM to be used as a trainer's party.(plus evs set by a var)

    Yea I understand that.


    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. :)

    MY question: could someone describe simplest way to go from numerator and denominator to a percentage? I found "Div," but I'm not sure how to utilize what "Supervisor Mode " 6 does. I specifically would like a rounded percentage as an integer, not the number of times the numerator goes into the denominator/ignoring remainder.

    So you want to get a percentage which takes the remainder into account when rounding? Hmm, I don't believe such a built-in function exists. What you can do is:

    Code:
    main:
    	push {r4, lr}
    	mov r0, numerator
    	mov r1, denomenator
    	mov r4, r1
    	swi #0x6
    	lsr r1, r1, #0x2
    	lsr r4, r4, #0x2
    	cmp r4, r1
    	bhi end
    
    round:
    	@calculating how much percent to add is a pain in itself...
    	push {r0}
    	mov r0, r1
    	mov r1, #0x64
    	swi #0x6
    	mov r1, r0
    	pop {r0}
    	add r0, r0, r1
    	
    end:
    	pop {r4, pc}

    swi 0x6 does modulo division and normal division. The modulo return is in r1 and normal version is in r0 with abs in r3. From there you need to check if the modulo / 2 > denominator/2 and manually increment the percentage if this is the case. Above is untested.
     
    Last edited:
  • 417
    Posts
    9
    Years
    • Seen Nov 20, 2016
    So you want to get a percentage which takes the remainder into account when rounding? Hmm, I don't believe such a built-in function exists. What you can do is:

    swi 0x6 does modulo division and normal division. The modulo return is in r1 and normal version is in r0 with abs in r3. From there you need to check if the modulo / 2 > denominator/2 and manually increment the percentage if this is the case. Above is untested.
    Hmm. Well what I meant was that say you have the numerator = 40 and denominator = 200. Anyone could tell you that it is equivalent to 20%, but I wasn't sure on how to efficiently write it as a routine that takes #40 and #200 and returns #20.

    I'm not sure I understand the code that you wrote out. Especially the part where you mentioned modulo / 2 and denominator / 2. Are those division signs? Because in the code, you logical shifted right by two, which would be more closely estimated as division by four? And when I plugged a few numbers in, it didn't seem to return what I wanted. Does it only work for numerator > denominator and the return is greater than 100%?

    I'm not sure whether my lack of understanding on the code is due to not being well versed in bit logic or being bad at math :P Either way, the information on swi 0x6 is useful by itself. I didn't expect anyone to write out an actual code, so I appreciate that!
     

    Blah

    Free supporter
  • 1,924
    Posts
    11
    Years
    Hmm. Well what I meant was that say you have the numerator = 40 and denominator = 200. Anyone could tell you that it is equivalent to 20%, but I wasn't sure on how to efficiently write it as a routine that takes #40 and #200 and returns #20.

    I'm not sure I understand the code that you wrote out. Especially the part where you mentioned modulo / 2 and denominator / 2. Are those division signs? Because in the code, you logical shifted right by two, which would be more closely estimated as division by four? And when I plugged a few numbers in, it didn't seem to return what I wanted. Does it only work for numerator > denominator and the return is greater than 100%?

    I'm not sure whether my lack of understanding on the code is due to not being well versed in bit logic or being bad at math :P Either way, the information on swi 0x6 is useful by itself. I didn't expect anyone to write out an actual code, so I appreciate that!

    Yeah, you're right, it should've been lsr #0x1, and those "/" are division signs (I'm not sure how I'd go about making the division symbol on a keyboard) whoops.

    Yes, it should work for all cases, try it with the lsr #0x1.
     
  • 76
    Posts
    9
    Years
    MY question: could someone describe simplest way to go from numerator and denominator to a percentage? I found "Div," but I'm not sure how to utilize what "Supervisor Mode " 6 does. I specifically would like a rounded percentage as an integer, not the number of times the numerator goes into the denominator/ignoring remainder.
    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.
     
  • 5,256
    Posts
    16
    Years
    FireRed actually has two routines for integer division:

    DivMod1 (Takes in R0 as Numerator and R1 as Denominator; Returns INTEGER DIVISION (9/2 = 4 r 1) result to R0): 0x1E4018
    DivMod2 (Takes in R0 as Numerator and R1 as Denominator; Returns REMAINDER OF INTEGER DIVISION (23/4 = 5 r 3 to R0): 0x1E4684
     
    Status
    Not open for further replies.
    Back
    Top