• 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.

Blah

Free supporter
  • 1,924
    Posts
    11
    Years
    What's the most idiomatic way to clear all but the least significant byte from a register?

    I currently have two thoughts:

    Code:
    lsl r1, r1, #0x18
    lsr r1, r1, #0x18

    Code:
    mov r0, #0xFF
    and r1, r0

    I like the first because I don't have to use a second register, but the second is a bit clearer, and I'm guessing, faster. Which one should I go with? Or perhaps even a different alternative I haven't considered?

    For the first one, you're losing the significant byte.
    You've got the shifts backwards. Clearing the last byte would be done like this:

    Code:
    lsr r0, r0, #0x8
    lsl r0, r0, #0x8

    Say you have FFFF. Shifting it right 8 bits (1 byte) gives you 0FFF, then you shift it left 8 more bits to get FFF0 :)
     
  • 788
    Posts
    17
    Years
    • Seen May 26, 2024
    For the first one, you're losing the significant byte.
    You've got the shifts backwards. Clearing the last byte would be done like this:

    Code:
    lsr r0, r0, #0x8
    lsl r0, r0, #0x8

    Say you have FFFF. Shifting it right 8 bits (1 byte) gives you 0FFF, then you shift it left 8 more bits to get FFF0 :)

    Sorry, I may have been a little unclear. I'm trying to get clear all but the least significant byte. As in, if you have FFFF, you shift up to F000, and then back down to 000F.
     

    Blah

    Free supporter
  • 1,924
    Posts
    11
    Years
    Sorry, I may have been a little unclear. I'm trying to get clear all but the least significant byte. As in, if you have FFFF, you shift up to F000, and then back down to 000F.
    Oh, looks like I've read incorrectly. Yeah, shifting would be faster and better.
     

    GOLDstandard

    Eclectic
  • 51
    Posts
    10
    Years
    A friend shared with me this script to check a pokemon's ability:
    ldrb r0, [08XXXXXX] (=$02023D6B) offsetof the Pokémon attacking
    mov r1, #0x58
    mul r0, r1
    ldr r1, [08XXXXXX] (=$02023BE4)Offset for all of the 4 Pokémon's datas each Pokémon takes 58 bytes of data according to bulbapedia
    add r1, r1, r0
    add r1, r1, #0x20
    ldrb r1, [r1]
    cmp r1, #0x? with the ? as the ability I want to check
    Now I do various things based on what the ability is correct? How and where do I place this within the ROM? I am just having trouble in general finding where I am supposed to put my scripts in general so that the game checks for it without replacing existing code
     
    Last edited:

    Blah

    Free supporter
  • 1,924
    Posts
    11
    Years
    A friend shared with me this script to check a pokemon's ability:
    ldrb r0, [08XXXXXX] (=$02023D6B) offsetof the Pokémon attacking
    mov r1, #0x58
    mul r0, r1
    ldr r1, [08XXXXXX] (=$02023BE4)Offset for all of the 4 Pokémon's datas each Pokémon takes 58 bytes of data according to bulbapedia
    add r1, r1, r0
    add r1, r1, #0x20
    ldrb r1, [r1]
    cmp r1, #0x? with the ? as the ability I want to check
    Now I do various things based on what the ability is correct? How and where do I place this within the ROM? I am just having trouble in general finding where I am supposed to put my scripts in general so that the game checks for it without replacing existing code

    This is probably not what you're looking for. Those offsets are for battle data. In the battle it records various things about each combatant and one of the things happens to be ability.

    If you just want to check the Pokemon's ability in overworld it would be different. You'd use the Pokemon decrypter to figure out which ability bit is turned on and depending on that, you would need to use the Pokemon Base stats table to search for which ability it currently has. Then, finally link the ability number to a string.

    I just wrote a routine that happens to do all that for you: https://www.pokecommunity.com/showpost.php?p=8533783&postcount=280
     

    Blah

    Free supporter
  • 1,924
    Posts
    11
    Years
    How do i make my routine read from a table? I think it would be different when hard coded or calling via script.

    You need to know the format of the table before you do anything. Most of the time tables in ROM are very easy, while tables in RAM require some sort of field for Table length. This is because

    In ROM, it's rather simple to read pointer and data it look like this:
    Code:
    main:
    	mov r2, #0x0
    loop:
    	ldr r0, .TableStart
    	lsl r1, r2, #0x2 @data length (I'm assuming it's a pointer, so multiply by 4)
    	add r0, r0, r1
    	ldr r0, [r0] @new pointer in table
    	lsr r1, r0, #0x18
    	cmp r1, #0xFF @end of table, you may want to use 00 00 00 00 as the ending bytes, however.
    	beq end
    	@right now r0 contains a valid pointer in the table
    	@you can bl to any other sub routines that utilize it here
    	
    next:
    	add r2, r2, #0x1 @increment table counter
    	b loop

    In RAM, depending on the contents of the table you may need a table counter. For example, in my Roaming Pokemon data structure, it was not always 100% chance that the last X bytes would be "00" and on top of that I want to be able to see if an Xth one is there (I don't want to be loading garbage data). So a table counter is very nice. However, if you're just writing something like a short table of strings, you can determine the end of the table because 0xFF is the string terminating byte.

    Code:
    main:
    	ldr r3, .TableLength
    	mov r2, #0x0
    loop:
    	cmp r3, r2 @check if we're finished the table
    	beq end
    	ldr r0, .TableStart
    	lsl r1, r2, #0x2 @data length (I'm assuming it's a pointer, so multiply by 4)
    	add r0, r0, r1
    	@right now, r0 contains a pointer to the start of the current data
    	@you can bl to any other sub routines that utilize it here
    	
    next:
    	add r2, r2, #0x1 @increment table counter
    	b loop

    You'll notice that I didn't need to check if it was the end of the table because I already know the length of the table. 1 extra byte in RAM space is saving up operation time. Worth? Yes.


    Finally, the last and probably the best way is if you already know which index you want.

    Code:
    main:
    	ldr r0, .TableStart
    	mov r1, #0x[data length]
    	mov r2, #0x[date index]
    	mul r1, r1, r2
    	add r0, r0, r1 @start of the new data

    Hope this helps. If you have questions, feel free to ask here :)
     
    Last edited:

    Blah

    Free supporter
  • 1,924
    Posts
    11
    Years
    Hi,

    Is it possible to call a XSE script from an ASM script ?

    Yes. You would make a routine which passes the script to the script executor. That will run your script. A few posts before, someone was attempting something similar, take a look.
     
  • 88
    Posts
    13
    Years
    • Seen Jun 18, 2020
    I think I'm wrong {XD}

    I have to simple XSE scripts. I want to call the second script in the first.

    XSE script #1 (at 0x900000) :
    Spoiler:


    XSE script #2 (at 0x910000) :
    Spoiler:


    And my ASM code (inserted at 0xB00000) :
    Spoiler:


    Note that the offset 69AE4 in an English Fire Red ROM corresponds with the offset 69B94 in a French Fire Red ROM (I use French ROMs).

    The result of the first XSE script should be two messages, "Script 1" then "Script 2", right ? Instead of it, when I talk to a person with the first XSE script, I can hear the Bulbasaur's cry, and there isn't any message.

    What's the matter ?
     

    Blah

    Free supporter
  • 1,924
    Posts
    11
    Years
    I think I'm wrong {XD}

    I have to simple XSE scripts. I want to call the second script in the first.

    XSE script #1 (at 0x900000) :
    Spoiler:


    XSE script #2 (at 0x910000) :
    Spoiler:


    And my ASM code (inserted at 0xB00000) :
    Spoiler:


    Note that the offset 69AE4 in an English Fire Red ROM corresponds with the offset 69B94 in a French Fire Red ROM (I use French ROMs).

    The result of the first XSE script should be two messages, "Script 1" then "Script 2", right ? Instead of it, when I talk to a person with the first XSE script, I can hear the Bulbasaur's cry, and there isn't any message.

    What's the matter ?

    Oh I see what you mean now. Well, I'm not sure how the limitations work for calling the script from ASM within a script. I'm pretty sure you're going to eventually overwrite parts of the stack. I would rather just use the scripting command "call" and have a return at the end of the second script. On another note, a quick peek at your routine tells me it doesn't look wrong :P
     
  • 88
    Posts
    13
    Years
    • Seen Jun 18, 2020
    Oh I see what you mean now. Well, I'm not sure how the limitations work for calling the script from ASM within a script. I'm pretty sure you're going to eventually overwrite parts of the stack. I would rather just use the scripting command "call" and have a return at the end of the second script. On another note, a quick peek at your routine tells me it doesn't look wrong :P

    Yes, of course, the command "call" is really easier to use, it was just to try the ASM code.

    So, if I understand, I can call a XSE script only when I'm in an ASM script not called from another XSE script ? x)
     

    Blah

    Free supporter
  • 1,924
    Posts
    11
    Years
    Yes, of course, the command "call" is really easier to use, it was just to try the ASM code.

    So, if I understand, I can call a XSE script only when I'm in an ASM script not called from another XSE script ? x)

    Yeah, I don't think you can load and run two instances of the script execution routine at once.
     
  • 88
    Posts
    13
    Years
    • Seen Jun 18, 2020
    Okay ! Another question related to the previous one : is it possible to run an XSE script from an item, changing the "Field Usage Code Pointer" in Item Editor ?
     

    Blah

    Free supporter
  • 1,924
    Posts
    11
    Years
    Okay ! Another question related to the previous one : is it possible to run an XSE script from an item, changing the "Field Usage Code Pointer" in Item Editor ?

    Yes, doing this has been documented in two different ways I know of, by davidjcobb (who uses JPAN's engine) and Darthatron who uses the script executor.
     

    daniilS

    busy trying to do stuff not done yet
  • 409
    Posts
    10
    Years
    • Seen Jan 29, 2024
    I think I'm wrong {XD}

    I have to simple XSE scripts. I want to call the second script in the first.

    XSE script #1 (at 0x900000) :
    Spoiler:


    XSE script #2 (at 0x910000) :
    Spoiler:


    And my ASM code (inserted at 0xB00000) :
    Spoiler:


    Note that the offset 69AE4 in an English Fire Red ROM corresponds with the offset 69B94 in a French Fire Red ROM (I use French ROMs).

    The result of the first XSE script should be two messages, "Script 1" then "Script 2", right ? Instead of it, when I talk to a person with the first XSE script, I can hear the Bulbasaur's cry, and there isn't any message.

    What's the matter ?

    In your routine, you don't need the +1 at the script address. And I expect "Script 2" to be shown before "Script 1", and maybe just Script 2.
     
  • 88
    Posts
    13
    Years
    • Seen Jun 18, 2020
    Another problem :(

    I used the Darthatron's code, and it works, but only when I use my item pressing Select. If I click on "Use" in the bag, nothing happens, except the bag closes (but no crash).

    Here's the ASM code with French Offsets :
    Spoiler:

    My XSE script is compiled at 0x900000. In Item Editor, I put C00001 at "Field Usage Code Pointer", because my ASM code is compiled to 0xC00000.


    EDIT : I didn't see your post !

    In your routine, you don't need the +1 at the script address. And I expect "Script 2" to be shown before "Script 1", and maybe just Script 2.

    You're right, it works ! And effectively, just "Script 2" is shown.

    But I can't use XSE scripts with items if I don't register them...
     
    Last edited:

    JoshTheTrainer

    Glaceon Lover ~
  • 101
    Posts
    15
    Years
    Oh, I've done some research on this before :D

    The Map's name is based on the map value (I think that's what it's called), it's a byte in the map header.
    You will need to change this to an unused byte value and then do some editing\expansion on the routine at 080C4D78. This routine takes the following parameters:
    r0: Location to store string
    r1: Map value byte (I was just talking about)
    r2: ??? I just use 0x0, though for your purposes it doesn't matter.

    Basically it's the routine that will read Map names. There's some calculations and stuff that go on in there which you may want to edit slightly for it to return a map name of your liking. The easiest way is to hook from the start, make an exception case for your specific map value.

    Code:
    Main:
    	push {r0-r3}
    	cmp r1, #0x[your custom map value]
    	bne default
    
    forceName:
    	ldr r1, =(0x8[pointer to your map's name in hex])
    	ldr r2, =(0x8008D84 +1) @str_cpy
    	bl linker
    	b end
    
    linker:
    	bx r2
    
    default:
    	pop {r0-r3}
    	@restore overwritten instructions
    	@bx to appropriate location to continue safely
    	@note these comments are for you to fill in with the appropriate assembly instructions
    
    end:
    	pop {r0-r3}
    	ldr r4, =(0x80C4DF2 +1)
    	bx r4


    Hopefully that helps (it should, as I practically spoon fed you the solution :P). If you have ASM questions ask in the Assembly Help thread :D

    I was wondering if somebody can explain me more of this. For example, I know it's ASM but how do I insert it in my rom? Do I need to disassemble it and go to the right 'memory location' or what? Sorry if I sound a bit noobish but I'm not an expert.
     

    Blah

    Free supporter
  • 1,924
    Posts
    11
    Years
    I was wondering if somebody can explain me more of this. For example, I know it's ASM but how do I insert it in my rom? Do I need to disassemble it and go to the right 'memory location' or what? Sorry if I sound a bit noobish but I'm not an expert.

    You would insert it right after the push for the function, which would be at 080C4D7A. Though you may obviously note that this is not a word aligned offset so you'd pad it with 2 bytes of zeros to reach 080C4D7C. From there you insert to that offset in a hex editor, the hex you get after compiling:
    Code:
    ldr r6, =(0x8[Custom snip +1])
    bx r6

    Custom snip would be the pointer to map name assigning routine from last post +1. You may notice we've overwritten some instructions for our little jump. You have to edit
    Code:
    default:
    	pop {r0-r3}
    	@restore overwritten instructions
    	@bx to appropriate location to continue safely
    	@note these comments are for you to fill in with the appropriate assembly instructions
    to include those instructions, and use a safe register to return to some non-junk code which would run subsequently after and at the same time not mess up existing register values.
     

    JoshTheTrainer

    Glaceon Lover ~
  • 101
    Posts
    15
    Years
    You would insert it right after the push for the function, which would be at 080C4D7A. Though you may obviously note that this is not a word aligned offset so you'd pad it with 2 bytes of zeros to reach 080C4D7C. From there you insert to that offset in a hex editor, the hex you get after compiling:
    Code:
    ldr r6, =(0x8[Custom snip +1])
    bx r6

    Custom snip would be the pointer to map name assigning routine from last post +1. You may notice we've overwritten some instructions for our little jump. You have to edit
    Code:
    default:
    	pop {r0-r3}
    	@restore overwritten instructions
    	@bx to appropriate location to continue safely
    	@note these comments are for you to fill in with the appropriate assembly instructions
    to include those instructions, and use a safe register to return to some non-junk code which would run subsequently after and at the same time not mess up existing register values.

    And that's in the assembly of my rom, right? So I just need a disassembler and assembler or is it just basic script editing?
     
    Status
    Not open for further replies.
    Back
    Top