PHO - Pokémon Hackers Online
Go Back   PHO - Pokémon Hackers Online > Discussion Board > Archive

Notices

Archive Old threads that serve no purpose are here.

 
 
Thread Tools Display Modes
Old 1st October 2010, 10:02 PM   #1
Shiny Quagsire
Super Awesome Ninja ASM Guy
PHO VIP
 
Shiny Quagsire's Avatar
 
Join Date: Apr 2010
Age: 20
Posts: 62
Shiny Quagsire
Default GBA ASM Programming




GBA ASM Programming
From scratch and on Pokemon Games



Introduction

If you've ever had to learn about computers, most people say: "The computer uses 0's and 1's," and "Programmers write applications all in 0's an 1's." That's only partially true. Machine code usually is written in C/C++, which is then compiled to Assembly Code, and then 1's and 0's.

What is Assembly Language

ASM is a low-level language that (When compiled) processors use to interpret instructions. Here's how Wikipedia defines it:


Assembly language is a low-level programming language for computers, microprocessors, microcontrollers, and other integrated circuits. It implements a symbolic representation of the binary machine codes and other constants needed to program a given CPU architecture. This representation is usually defined by the hardware manufacturer, and is based on mnemonics that symbolize processing steps (instructions), processor registers, memory locations, and other language features. An assembly language is thus specific to a certain physical (or virtual) computer architecture.



The processor and ASM language the GBA uses is ARM 7, (which is a lot easier compared to Z80, the GBC processor, in my opinion). When you write ASM, All you can do is Add, Subtract, Multiply, load data, and store data. There is no magical "Change the name" command.

You may have noticed there is no divide. The problem is that there are no decimals in ARM 7 ASM, and division is generally harder on the processor to calculate. There are BIOS functions to divide, but there are some tricks to doing simple dividing that I'll explain later.


What We'll need:
  1. VisualBoyAdvance
  2. A compiler - To put our ASM into Hex
  3. VBA-SDL-H - For testing, or debugging, our ASM to see how it works or to find problems.
  4. A Brain XD


Let Me Try! Let Me Try!

I think the best way of learning is to let you see what you can do with this knowledge. So, first, download my ASM Pack, which includes:
  1. A compiler
  2. HackMew's Nifty Batch File - Thanks HackMew!
  3. Some ASM Code

With that downloaded and extracted, go into the command prompt. After all, the assembler is command prompt based.

If you don't know how to use the command prompt, just google 'Command Prompt Tutorials.' You'll find something ;)

When you open it, you'll see somthing similar to this:


Microsoft Windows XP [Version 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.

C:\Documents and Settings\XXXXXX>


Now, navigate to the directory you placed it in. For me, it's in a folder on my desktop called ASM. Try to keep folder names short, and simple.

Microsoft Windows XP [Version 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.

C:\Documents and Settings\Maxamillion>cd Desktop\ASM\tutorial

Now we need to assemble it, so type in this:
Code:
thumb example1.asm example1.bin
Here's our output:

Microsoft Windows XP [Version 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.

C:\Documents and Settings\Thomas>cd Desktop\ASM\tutorial
C:\Documents and Settings\Thomas\Desktop\ASM\tutorial>thumb example1.asm example1.bin
Assembled successfully.
Press any key to continue . . .


Obviously press any key, and we're done!


What a Piece of Junk!

OK, so we assembled our routine, but how do we use it?! First, open up our example1.bin we assembled into a hex editor. You should get something like this:


03 B5 02 48 80 88 02 49 08 80 03 BD 84 42 02 02 D0 70 03 02


Now, open your Pokemon ROM into a hex editor, and copy it to a free-space address ending with 0, 4, 8, or C. You may ask, "Why not 5? or 7?" Because these numbers aren't multiples of four, and it uses bit 0, a bit used to tell the game "Do you want to boot into Thumb or ARM?" So, once you have it copied, you'll need to set bit 0 to 1, or, simply put, add 1 to your offset. So if I placed it at 0x720000, I'd add 1, making it 0x720001.

With this inserted, how do we use it through a script? (Please note this is an ASM tutorial, and no questions regarding scripting will be answered, unless it's a problem with booting the ASM in the script.) The answer is simple. We use the magical callasm command. So, here's an example script to use, since you don't know how the ASM works yet.


#dynamic 0x800000

#org @start
lock
faceplayer
callasm 0xsomeoffset
buffernumber 0x0 lastresult
msgbox @msg 0x2
release
end

#org @msg
= Wow, your POKEMON is at level [buffer1]!


Once that's inserted, go ahead and go to VisualBoyAdvance and open your script. Here's what your result should look like:


But was that it's level? Let's check!


There it is! But how'd the ASM return it? That will be explained in the next section.


Looking? Found someone you have, eh?
~Yoda


Alright, so we've had some fun, but we've never seen what's going on in the ASM, or the script. Now let's see how it works by looking at Pokemon data, then explain each command one by one in the ASM routine.

Pokemon Data
The Pokemon data can be explained in detail here. You can check it out to see where some things are. The stats and such don't start untill about byte 80.
The byte we are retrieving, is the level, 1 byte with a maximum of 256. Let's see how we load those bytes by opening the ASM file according to your game. They'll all be slightly different, but they all have the same commands at a glance.

.align 2
This aligns the ASM by a multiple of 2, since each instruction is 2 bytes long.

.thumb
This tells the assembler that we are using the thumb instruction set. If we were using ARM, we'd use .ARM

main:
This is label. Labels are ways to call parts of a routine without calculations or repeating things over and over. Labels are text (Without spaces), and end with a colon. This label is called "main"

push {r0-r1,lr}
This pushes registers r0, r1, and the link register into the stack.

Registers are like variables that store temporary values and information. Registers are 32 bits long, making the highest value possible FFFFFFFF.
The stack is a bit hard to explain. Think of 15 stacks of china plates. Each of them has a different design on them. When you push a register into the stack, it's like adding a new plate as the one on the top to the stack. Here's a visual representation from Wikipedia:

The Link Register tells the processor where to return from the parent routine that called this one.

ldr r0, pokemon_data
This loads a 32 bits at the label 'pokemon_data' into r0. These bits, or bytes contain the address to our party data.

ldrh r0, [r0]
Loads a 'half-word,' or 16 bits, (or 2 bytes) from the address at r0.

ldr r1, var
This loads the data at the label var, which is the location of LASTRESULT in the WRAM. (Work RAM)

strh r0, [r1]
This stores the half-word in r0 at the address in r1. But r0 has a byte, not a half-word! It stores a half-word, not because r0 has a half word, but variables are only 1 half-word long.

pop {r0-r1,pc}
This 'pops,' or removes the registers r0, r1, and pc from the top of the stack, leaving the original registers again. You may ask "Why not pop {r0-r1, lr}? Well, pc is our current position. When we pop this, It continues onto where it was before. The link register will reset by itself. Here's the image again to help explain:


.align 2
We need to make sure our variables are multiples of two, so the routine can access them.

pokemon_data:
Another label, giving our Pokemon data.

.word 0x02024284 + 0x54
Writes the word 0x02024284 + 0x54 at this spot.

var:
A label for our variable.

.word 0x020270B6 + (0x800D * 2)
The offset of the first variable plus 0x800D, the lastresult variable, x 2, since variables are 2 bytes long.



Returning Values at the Bit Level

Alright, we've checked code, we've disected code, now lets go even deeper into pokemon values!

What New Commands We'll need:
lsl rX, #0xV - This shifts the bits in rX left byte 0xV positions.
lsr rX, #0xV - This does the same as above, but shifts bits right.
ldrb rX, [rY, #0xV] - Loads a byte from the address at rY + 0xV into rX. The 0xV is optional though.
There are also other methods that you can use, and it's usually the same with all ldr commands.
ldrb rX, label - Loads a byte from a label.

What we'll be doing
I decided to make a tutorial with something to the bit level. After all, bits are hard to manipulate at first, but it's key to disecting some things.

Status Conditions
Status conditions are based on bits. Here's a quote from bulbapedia:
Quote:
Originally Posted by Bulbapedia

Status ailment


The Pokémon's status ailments are stored as follows:
  1. 0-2: Sleep bits. Indicates turns of sleep, so 111b = 7 turns, 101b = 5 turns, etc.
  2. 3: Poison
  3. 4: Burned
  4. 5: Frozen
  5. 6: Paralysis
  6. 7: Bad poison
Now, let's see how we can get, say, the sleeping bit perhaps. Let's write some code!

Down and Dirty!
Alright, lets get to work. First, create a brand new txt file, and rename it Status_[gameprefix].asm the game prefix should be like my example1_fr, or example1_rs. Try to keep names without spaces, and short and sweet.

Now, add this to the top of your file:
Code:
.align 2
.thumb

main:
		push {r0-r1,lr}
		ldr r0, pokemon_data
That is the start of our first code, but we need to load a byte at 80 bytes afterwards, or 0x50 bytes.
Code:
ldrb r0, [r0]
Now, lets say we wanted to get the sleeping bits. We'd have to shift everything over left by 5 spaces,leafing the three sleeping bits. And since it has the number of turns asleep, that could be what we return!
Code:
lsl r0, #0x5
lsr r0, #0x5
What this does is takes a value like:
10101010
turns it into this:
01000000
Then this:
010
Which is the sleep value!
And now we write it to the variable 0x800D
Code:
		ldr r1, var
		strh r0, [r1]
		pop {r0-r1,pc}
Now, take the bottom labels starting at the second .align 2 from the previous code file. Also, add "+ 0x50" to the end of pokemon_data.
For example, I'd add this:
Code:
.align 2

pokemon_data:
		.word 0x02024284 + 0x50
var:
		.word 0x020270B6 + (0x800D * 2)
Alright, lets give it a test run! Go ahead and compile it with thumb.bat. Here's an example script we can use.
Code:
#dynamic 0x800000

#org @start
lock
faceplayer
callasm 0xyouroffset
buffernumber 0x0 lastresult
msgbox @msg 0x2
release
end 

#org @msg
= That POKEMON sure is sleepy.\nIt's going to sleep [buffer1] turns!
Now attach that script to someone, and lets go!



Of course, my pokemon wasn't asleep, but it returned the value. Feel free to debug it if you want!

The Challenge of the Day!


Can you return the value of a burn? Perhaps poison? Return your ASM with an image!


Value Changing, Comparing, and Arithmetic Commands

In this tutorial, we're going to cover commands used to change value, compare, and do arithmetic functions, which are some of the most essential commands (In my opinion) to ARM7 ASM.

New Commands used in this Section:
mov rX, #0xY Moves the value in rX to 0xY.
add rX, rY, rZ Adds the contents of rY and rZ and places it on rX.
add rX, #0xY Adds 0xY to rX.
sub rX, rY, #0xZ Subtracts 0xZ from rY and places it on rX. It generally has the same syntax as adding.
mul rX, rY, rZ Multiplies rY and rZ and places the result on rX. rZ cannot be replaced with a hex number like #0x5.
cmp rX, #0xY Compares the value in rX to 0xY and stores the results to the flags. 0xY can also be a register.
teq rX, #0xY This is sort of a limited cmp command, that tests if rX is equal to 0xY.
b{condition} label Compares the flags depending on the condition, and if the result meets the condition, the processor goes to label.

Using Comparing Commands
Comparing commands work by subtracting 0xY from rX, and placing the results in the flags. It doesn't really return any result to a register. Here's a quote from ARM's website:
Quote:
Originally Posted by ARM.com
These instructions compare the value in a register with Operand2. They update the condition flags on the result, but do not place the result in any register.

The CMP instruction subtracts the value of Operand2 from the value in Rn. This is the same as a SUBS instruction, except that the result is discarded.
So, that's how it works. Unfortunatly, the flags are protected from access in thumb mode, but there is a command that can do it for us. It's the command "b".
Spoiler:



How 'b' works is it compares the flags to a condition. If it is met, it goes to another label. The conditions are as follows:
Code:
EQ	Equal
NE	Not equal
CS/HS	Higher or same (unsigned >= )
CC/LO	Lower (unsigned < )
MI	Negative
PL	Positive or zero
VS	Overflow
VC	No overflow
HI	Higher (unsigned <= )
LS	Lower or same (unsigned <= )
GE	Signed >=
LT	Signed <
GT	Signed >
LE	Signed <=
AL	Always (usually omitted, same as just "b" by itself.)
So bhi rX, rY would be like this equasion:
Code:
rX <= rY
If the equasion is true, it goes to the label. If not, it continues.

A Quick Example
For this, we won't have an active code sample that does something, simple because this is more for learning the commands. Instead, lets have some examples:
Code:
.align 2
.thumb

main:
		push {r0-r1}
		mov r0, #0x5 @Moves r0 to 5
		sub r0, #0x3 @Subtracts 3 from r0
		mov r1, #0x3 @Move r1 to 3
		mul r0, r1, r0 @multiplies r0 and r1, and places the result on r0
		cmp r0, #0x6 @Compares r0 to 6, which it should be
		beq end	       @If equal goes to the label 'end'
end:
		pop {r0-r1}
And that pretty much covers everything we need!



__________________





My Works:

Coming Soon/Working On:
  • Pokemon Amethyst
  • ?Using HMs via Items?
  • Custom GUIs using ASM (and soon) C



Last edited by Shiny Quagsire; 30th January 2013 at 04:27 AM.
Shiny Quagsire is offline  
Sponsored Links
Old 14th October 2012, 02:15 PM   #2
Linkandzelda
RHO つぃちょう
Webmaster
 
Linkandzelda's Avatar
 
Join Date: Apr 2012
Location: United Kingdom
Posts: 286
Linkandzelda Linkandzelda Linkandzelda
Default

This is a very sexy looking guide, good job!
__________________





Linkandzelda is offline  
Likes mewthree9000 liked this post
 

Tags
asm, gba, programming, [Tutorial]

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT. The time now is 07:59 AM.

Powered by vBulletin® Version 3.8.7
Copyright ©2000 - 2018, vBulletin Solutions, Inc. User Alert System provided by Advanced User Tagging (Lite) - vBulletin Mods & Addons Copyright © 2018 DragonByte Technologies Ltd.
Feedback Buttons provided by Advanced Post Thanks / Like (Lite) - vBulletin Mods & Addons Copyright © 2018 DragonByte Technologies Ltd.
Pokémon characters and images belong to Pokémon USA, Inc. and Nintendo.
Pokémon Hackers Online (PHO) is in no way affiliated with or endorsed by Nintendo LLC, Creatures, GAMEFREAK inc,
The Pokémon Company, Pokémon USA, Inc., The Pokémon Company International, or Wizards of the Coast.
All forum/site content (unless noted otherwise) and site designs are © 2006-2013 Pokémon Hackers Online (PHO).
Green Charizard Christos TreeckoLv100

"Black 2" by ARTPOP. Kyurem artwork by XOUS.

no new posts