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

GBA ASM Programming

colcolstyles

Yours truly
1,588
Posts
15
Years
  • quick question, how would i make a pokemon base stat go higherthan 255? i know this requirs asm and if i over looked it and its in this tut plz tell me so your time isn't wasted any more

    You will have to expand the pokémon data structure so that the six base stats will all be halfowrds (16-bit) instead of bytes (8-bit). You will also have to change the references to the data table because each entry (i.e., each pokémon's data) will now be longer. Then you'll have to hunt down every single routine that loads a pokémon's base stats and change them so that each one loads halfwords instead of bytes. You possibly will also have to make some changes to these routines as they will be interpreting the data as bytes.

    In other words, just give up.
     
    94
    Posts
    13
    Years
    • Seen Nov 2, 2016
    Quick question. When you load the status byte and want to separate the 3 sleep bits, why not just and it by 7? I'm just starting out with assembly but I was wondering why you shifted the bits to clear instead of just using and.
     

    Xenesis

    Syogun Changer
    55
    Posts
    18
    Years
  • Using shifts to clear bits has it's advantages. Mainly because to and something you need to load a value into a register and then and between two registers. Using bitshifts to cut off bits you don't care about is often simpler because it requires only one register.

    Basically, as a consequence of the processor design there's no function for AND rX, Value, just AND rX, rY

    Here's a summary of all the ALU operations from gbatek:

    Code:
    THUMB.4: ALU operations
    
    Opcode Format
    
      Bit    Expl.
      15-10  Must be 010000b for this type of instructions
      9-6    Opcode (0-Fh)
               0: AND Rd,Rs     ;AND logical       Rd = Rd AND Rs
               1: EOR Rd,Rs     ;XOR logical       Rd = Rd XOR Rs
               2: LSL Rd,Rs     ;log. shift left   Rd = Rd << (Rs AND 0FFh)
               3: LSR Rd,Rs     ;log. shift right  Rd = Rd >> (Rs AND 0FFh)
               4: ASR Rd,Rs     ;arit shift right  Rd = Rd SAR (Rs AND 0FFh)
               5: ADC Rd,Rs     ;add with carry    Rd = Rd + Rs + Cy
               6: SBC Rd,Rs     ;sub with carry    Rd = Rd - Rs - NOT Cy
               7: ROR Rd,Rs     ;rotate right      Rd = Rd ROR (Rs AND 0FFh)
               8: TST Rd,Rs     ;test            Void = Rd AND Rs
               9: NEG Rd,Rs     ;negate            Rd = 0 - Rs
               A: CMP Rd,Rs     ;compare         Void = Rd - Rs
               B: CMN Rd,Rs     ;neg.compare     Void = Rd + Rs
               C: ORR Rd,Rs     ;OR logical        Rd = Rd OR Rs
               D: MUL Rd,Rs     ;multiply          Rd = Rd * Rs
               E: BIC Rd,Rs     ;bit clear         Rd = Rd AND NOT Rs
               F: MVN Rd,Rs     ;not               Rd = NOT Rs
      5-3    Rs - Source Register       (R0..R7)
      2-0    Rd - Destination Register  (R0..R7)

    As you can see, they only work between two registers (with the exception of the NOT/NEG operations).
     
    Last edited:
    94
    Posts
    13
    Years
    • Seen Nov 2, 2016
    Using shifts to clear bits has it's advantages. Mainly because to and something you need to load a value into a register and then and between two registers. Using bitshifts to cut off bits you don't care about is often simpler because it requires only one register.
    If I'm not mistaken though and directly edits the contents of one register, so it only requires one register as well.
     

    colcolstyles

    Yours truly
    1,588
    Posts
    15
    Years
  • I'm pretty sure it takes two. Let's say you have some value in r0. In order to clear the top 29 bits, you would have to load 7 into an arbitrary register and then AND the two. I can't think of any way to do it with only one register other than to use logical shifts. Plus, I think that the "mov" instruction takes up more cycles than logical shifts so it'll save you a nanosecond or two. :D
     

    Xenesis

    Syogun Changer
    55
    Posts
    18
    Years
  • If I'm not mistaken though and directly edits the contents of one register, so it only requires one register as well.

    Yes, that's correct.

    However, you can't AND an immediate value in code, you have to AND two registers.

    Eg, you can't go:

    AND r0, #0x3

    because the hardware doesn't support it.

    You have to go something like:

    MOV r1, #0x3
    AND r0, r1

    Which requires two free registers. If you want to clear bits, you can just do something like:

    lsl r0, r0, #0x19
    lsr r0, r0, #0x19

    Which only requires one free register.

    Plus, I think that the "mov" instruction takes up more cycles than logical shifts so it'll save you a nanosecond or two. :D

    The difference between the two is generally rather minor. You're unlikely to add much bloat to the game's code as is unless you start abusing swi operations relentlessly.
     

    colcolstyles

    Yours truly
    1,588
    Posts
    15
    Years
  • The difference between the two is generally rather minor. You're unlikely to add much bloat to the game's code as is unless you start abusing swi operations relentlessly.

    True, although if the code is in a loop and you're already pressed for time (which you shouldn't be if you're hacking a commercial ROM), it could possibly make a difference. Actually, if this is to be used in a loop, you're probably better off "mov"-ing the 7 into a register outside the loop so that you only need one instruction (an "and") to clear bits while inside the loop.
     
    94
    Posts
    13
    Years
    • Seen Nov 2, 2016
    Thanks Xenesis, colcolstyles. There was just one more thing that wasn't clear to me:
    .word 0x020270B6 + (0x800D * 2)
    If the 0x8000-0x8013 variables are the only static one, how would there be an address of the "first" variable(I assume 0x0000), wouldn't it be DMA along with the rest?

    BTW, looking at an example code from a tutorial JPAN posted a while ago, he subtracts 0x8000 from his variable values, multiplies them by 4, then finally adds that to the 0x8000 variable's address. I don't understand why it would be necessary to do that(or how that works quite frankly), even though with the code in this tutorial you can simply store the value to loaded variable.
    Here was the code:
    Code:
                              .align 2
                              .thumb
      Var_adder:      push {r0-r2, lr}
                              Ldr r0, first_var_addr @this will load the address of that lable
                              Ldrh r0, [r0, #0x0]      @and this will load its content.
                              Ldr r1, second_var_addr
                              Ldrh r1, [r1, #0x0]      @both variable numbers are loaded   
                              Lsl r2, r2, #0x10          @cleans the bottom half of register r2
                              Add r2, r2,#0x8          @places 0x8 in r2
                              Lsl r2, r2, #0xc            @and this turns 0x8 in 0x8000, and cleans the rest                                                               @of r2             
                              Sub r1, r1, r2               @leaves only the last value in
                              Sub r0, r0, r2               @each variable.
                              Lsl r1, r1, #0x2            @after multiplied by 4, It becomes the 
                                                                  @offset of that address
                              Ldr r2, var_8000_addr
                              Lsl r0, r0, #0x2            @same here.
                              Add r0, r2, r0              @by adding the variable address to the offest
                              Add r1, r2, r1              @you get the correct variable address
                              Ldrh r2, [r0, #0x0]      @now we load the content of the variables we
                              Ldrh r1, [r1, #0x0]      @want to add
                              Add r2, r1, r2              @and add them
                              Strh r2, [r0, #0x0]       @the result, that is in r2, is placed in the first                                                                        @variable, the one in 0x8013
                              Pop {r0-r2, pc}           @and we're done
       
      first_var_addr: .word 0x020370dc
      second_var_addr:.word 0x020370de
      var_8000_addr:.word 0x020370b8
     

    阴魂君

    _(:зゝ∠)_ so busy i am…
    22
    Posts
    11
    Years
  • Excuse me,I don't know why,but I can't download the asm pack in China... Could you please send it to my email? My email address is [email protected]
    thanks a lot >_<
     
    33
    Posts
    10
    Years
    • Seen Sep 23, 2022
    Just curious here, I would need to use ASM to block players from challenging certain trainers (Gym Leaders, Rivals) with pokémons above a certain level, right?
    What if I need to block items during a certain battle?

    I'm just starting out, so I wanted to make my first hack more simple to understand mapping and scripting better, but if I need ASM to get some level and item caps then I'll have to learn it as well.

    Thanks for the tutorial, looks very interesting, I'll definitely read it later.
     

    Blah

    Free supporter
    1,924
    Posts
    11
    Years
  • Just curious here, I would need to use ASM to block players from challenging certain trainers (Gym Leaders, Rivals) with pokémons above a certain level, right?
    What if I need to block items during a certain battle?

    I'm just starting out, so I wanted to make my first hack more simple to understand mapping and scripting better, but if I need ASM to get some level and item caps then I'll have to learn it as well.

    Thanks for the tutorial, looks very interesting, I'll definitely read it later.

    For blocking players from challenging certain trainers depending on party pokemon level you need some asm, but it's just function calls, nothing down and dirty.

    For the item one, you'd need a battle script (look up Jambo's battle script tutorial/tool). Though admittedly, battle scripts are also very technical P:
     
    33
    Posts
    10
    Years
    • Seen Sep 23, 2022
    For blocking players from challenging certain trainers depending on party pokemon level you need some asm, but it's just function calls, nothing down and dirty.

    For the item one, you'd need a battle script (look up Jambo's battle script tutorial/tool). Though admittedly, battle scripts are also very technical P:

    Really? That's great news!

    Mind to elaborate what asm routines I would need to do the level caps?
    I really don't want to go in blind and break the game.
    And are you saying that locking the items mid-battle require just some scripting? Can it be done in XSE or would I need Jambo's tool?

    Thanks for the answers. Really helped.
     

    Blah

    Free supporter
    1,924
    Posts
    11
    Years
  • Really? That's great news!

    Mind to elaborate what asm routines I would need to do the level caps?
    I really don't want to go in blind and break the game.
    And are you saying that locking the items mid-battle require just some scripting? Can it be done in XSE or would I need Jambo's tool?

    Thanks for the answers. Really helped.

    Sure, for the prevention of player challenging trainers, it's 90% handled by the trainer script.

    I would do this:
    Code:
    #dyn 0x740000
    #org @start
    lock
    faceplayer
    setvar 0x4011 0x[max level of trainer]
    callasm 0x[asm that returns max pokemon level in party]
    compare 0x4001 LASTRESULT
    if > jump @ignore
    trainerbattle 0x0 0xID 0x0 @intro @defeat
    msgbox @afterwards
    callstd MSG_NORMAL
    release
    end
    
    #org @ignore
    msgbox @noThanks
    callstd MSG_NORMAL
    release
    end
    
    #org @noThanks
    = Sorry, you wouldn't be a\nchallenge to me!
    
    #org @intro
    = Battle started, say something
    
    #org @defeat
    = defeat text
    
    #org @afterwards
    = Nice battle.

    For the item blocking, I have no idea. I think Jambo's tutorial on Battle scripts covers it iirc.
     

    ZapdosMan

    The Principality
    38
    Posts
    9
    Years
    • Seen May 15, 2016
    Wow I think this is a really good tutorial
    though i find it hard to understand but finally someone posted a tutorial on this

    Thanks

    ZapdosMan
     

    Sounak

    Black Charizard
    7
    Posts
    9
    Years
    • Seen May 1, 2018
    The download link to your ASM pack is not working.
    Can you re-upload it please.
     
    794
    Posts
    10
    Years
  • I have a problem with your first routine. Here's what I got http://i.imgur.com/obuckLm.png
    My code:
    Spoiler:

    I also tried those ( 03 B5 02 48 80 88 02 49 08 80 03 BD 84 42 02 02 D0 70 03 02 ) assembled numbers and still got the same result. Why is this happening?
     

    GoGoJJTech

    (☞゚ヮ゚)☞ http://GoGoJJTech.com ☜(゚ヮ゚☜)
    2,475
    Posts
    11
    Years
  • I have a problem with your first routine. Here's what I got http://i.imgur.com/obuckLm.png
    My code:
    Spoiler:

    I also tried those ( 03 B5 02 48 80 88 02 49 08 80 03 BD 84 42 02 02 D0 70 03 02 ) assembled numbers and still got the same result. Why is this happening?

    That routine seems to be a failure. You're trying to load the level but you're loading a halfword (two bytes).
    Change "ldrh r0, [r0]" to "ldrb r0, [r0]"
     
    Back
    Top