• 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?".
  • Forum moderator applications are now open! Click here for details.
  • 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.

Development: [FR] Replacing the GameFreak Intro

Shiny Quagsire

I'm Still Alive, Elsewhere
697
Posts
14
Years
[FR,EM] Replacing the GameFreak Intro

Introduction
So several months back I was browsing through the ASM in Fire Red in IDA Pro, and I happened to stumble upon a few callback functions that knizz had found. After researching a few of them, I had discovered that some were empty or had very few functions in them. Using those functions, I recreated an empty callback, essentially giving me a way to leech into and replace certain callbacks with my own.

So I devised a way to test this empty callback. After seeing yet another post by knizz on how to skip to the titlescreen after the copyright, I decided to leech into that calling method, use it to call my code, and return to the titlescreen. It worked.

This is the code I used as my blank callback:
Code:
.text
.global callback

.thumb
.thumb_func
.align 2

main:
push {r0-r7, lr}
bl main_func
bl call_back3
bl sub_080704D0
pop {r0-r7, pc}

call_back3:
ldr r4, callback3_address
bx r4

sub_080704D0:
ldr r4, loc_080704D0
bx r4

main_func:
push {lr}
bl increment_timer
bl getcurrentfunc

increment_timer: @This function will be used to keep a per-frame timer
ldr r0, vram          @similar to the one used at the titlescreen. We will use
ldrh r0, [r0]           @it to route our introduction scenes.
ldr r1, vram
add r0, #0x1
strh r0, [r1]
bx lr

returnmain:
pop {pc}

getcurrentfunc:

@This will be our future 'routing' function
@that we use to go to the various states of our intro.

b titlescreen
bx lr

titlescreen:
bl goto_titlescreen
pop {r0-r7,pc}

goto_titlescreen:
push {lr}
ldr r0, sub_0800CC7A
bx r0

.align 2
callback3_address:		.word 0x08077578+1
loc_080704D0:			.word 0x080704D0+1
sub_0800CC7A:			.word 0x0800CC7A+1

So if you wanted to insert this as it was right now, simply compile and insert the ASM and place the pointer (+1) at 0x0EC5D0.

Explanation

While it looks like quite a bit of code, it's actually quite simple. It first calls out main function where we update and draw all of our backgrounds and sprites. Then after that it calls a few functions that help drive the callback system in Fire Red, and returns. Currently it is set up so that immediately after the main function is called, the titlescreen is set to the top of the callback table, which allows us to exit our new "intro". As it is though, it isn't much. However, with a lot of coding it could be very easily possible to code out an entire custom introduction. However, there are a few limitations:
  1. You have to severely fragment your routine in order to prevent your branch-links from failing. BL's can only travel so far. I have already had this happen, and it seems that the only way around this is to split your ASM into multiple callbacks, which would require manual editing of each callback to link into eachother properly. It just makes it messy and difficult to work with, and even worse to debug.
  2. Coding an entire intro in ASM can be difficult, so finding a way to do it in C would be more optimal. DevKitARM seems to have this issue where it decides to assume your compiling it as a GBA ROM, which means it has a bunch of initiation stuff making it near impossible to exit. If anyone could find a way to simply compile the C directly to it's ASM equivalent, that would help a lot.
  3. This skips past everything after the copyright screen until the title screen, which may or may not be what you want. I personally wanted to replace only the GameFreak screen, and keep the other half of the introduction.
  4. Since your basing it off the callback system, you have to play by the rules of Fire Red. This means that you have to use their functions for things that you would normally do straightforward with ASM. For example, Fire Red uses DRM to copy the colors to the VRAM. As such, you have to use their color pallet at 0x020371F8. A few other important offsets are listed below:

Code:
vram:				.word 0x020370B8 		@Variable RAM (variables 0x8000 and up. I decided to use these since I could at least garantee that I wouldn't screw over gameplay by using a different RAM location)
bgpal:				.word 0x020371F8 		@Fire Red palette buffer
objpal:				.word 0x020371F8 + (0x200) 	@Fire Red palette buffer, plus 0x200 to get OBJ pallets
oam:				.word 0x03003128		@Fire Red OAM buffer

There are, however, some advantages to using ASM. The first and possibly best advantage is direct hooks into the functions in Fire Red. So as an example of exactly what you can do with both access to the GBA hardware as well as the functions on the ROM, I've made a video of my custom introduction that I'll most likely be using in any of my future hacks:

If your interested in the source code, you can download it from my GitHub here.

Implementation
So you want to create a new intro for your hack. Well, let's just say that it isn't exactly for the faint of heart, and it requires a lot of work, planning, and research. However, I will give you a basic layout of how I did mine.

To start, I fragmented my routine into easy, managable chunks of assembly, one file for one purpose. My file structure looked something like this:
callback.asm
graphics.asm
constants.asm
timeconstants.asm
quagsireintro.asm
images/
img_bins/​

Each file did exactly as it described. callback.asm was the main callback function, graphics.asm stored several image binaries (more on that later), constants.asm stored needed constants for loading and storing data, as well as several key functions, timeconstants.asm stored constants related to timing, and quagsireintro.asm stored the actual function called in constants.asm.

So to include all these files as if it were one giant ASM file, you simply do something like this:
Code:
.include "quagsireintro.asm"
.include "timeconstants.asm"
.include "constants.asm"
.include "graphics.asm"

So how do we time this so that we go to the right function at the right time? Well, a function named increment_timer is called every frame. The GBA renders it's graphics at an exact 60Hz, or 60 times a second. Knowing this, we can make a constant called second with it's value set to 0x35, since there are 60 frames per second, minus a few if you call certain functions.

So essentially, you want to create several constants for each length of time that you want to call your function, and if it exceeds it, call the next function and so on. Here's a clip of code that I used to control events in my callback.asm:
Code:
ldr r1, companyname
cmp r0, r1
ble shinyquagsire

ldr r1, companyname2
cmp r0, r1
ble shinyquagsire_2

ldr r1, companyname3
cmp r0, r1
ble shinyquagsire_3

ldr r1, companyname4
cmp r0, r1
ble shinyquagsire_4

ldr r1, pausebetween1
cmp r0, r1
ble returnmain

ldr r1, a_flash
cmp r0, r1
ble update_a_step

ldr r1, grass_pan
cmp r0, r1
ble update_gpan_step

bgt titlescreen
and the corresponding constants:
Code:
companyname:			.word (second * 4) + (second / 4) + (second / 16)
companyname2:			.word (second * 5) + (second / 4) + (second / 16)
companyname3:			.word (second * 6) + (second / 2)
companyname4:			.word (second * 6) + (second / 2) + (second * 2)
pausebetween1:			.word (second * 6) + (second / 2) + (second * 2) + (second * 2) - (second / 2)
a_flash:			.word (second * 6) + (second / 2) + (second * 2) + (second * 2) - (second / 2) + (second * 3)
grass_pan:			.word (second * 6) + (second * 2) + (second * 2) + (second * 2) - (second / 2) + (second * 3) + (second * 3)

So basically we compare r0, which contains the timer value, to each of these time constants, and if it's less than it we go to a particular function which controls the callback for that duration of time.

This is the C as you can see.
C what I did there? ;)

OK, lame puns aside, let's imagine that you want to create an introductory sequence that replicates that of Crystal. Well, it just so happens that I did that very thing:

Full source code and compilation instructions available at the FR-CrystalIntro project on my GitHub

It initially started as an experiment that was originally coded in ASM. I posted some screens of the unown A scene and it generated enough interest to make me want to continue it to the end of the Crystal intro. It took several days to finish though, and it was not an easy feat my any means.

One of the problems I ran into when coding this intro was the difficulty of writing in pure ASM, which I explained prior to this section. So I instead searched out a way to code it in C and with the help of Bond697 I was able to do just that. Here's the basis of how it worked. First I had to design a way to get my C code in without the issue of unneeded code or crashing. To do this, I came up with what I like to call a bootloader. Basically this piece of ASM is based off of the same routine we had before, but instead of calling a piece of ASM located in another file, we bl to the end of the file, which is where we will insert our C code. Then we do our thing in the C code, return, and the ASM takes up back home into the Fire Red main loop.

Here's the base code for the bootloader:
Code:
.text
.global callback

.thumb
.thumb_func
.align 2

main:
push {r0-r7, lr}
bl main_func
returnmain:
bl call_back3
bl sub_080704D0
pop {r0-r7}
ldr r0, returnloc
bx r0

call_back3:
ldr r4, callback3_address
bx r4

sub_080704D0:
ldr r4, loc_080704D0
bx r4

main_func:
push {lr}
bl C_hook
b returnmain

call_fadescreen:
mov r0, #0x1
neg r0, r0
mov r3, r2
mov r2, r1
mov r1, #0x0
str r1, [sp,#0x0]
mov r1, #0x0
ldr r4, =0x08070589;
bx r4

.align 2
callback3_address:		.word 0x08077578+1
loc_080704D0:			.word 0x080704D0+1
sub_0800CC7A:		.word 0x0800CC7A+1
unfadescreen_trigger:	.word 0x020370B6
returnloc:			        .word 0x0800053a+1
			                .word 0x00000000
   		                        .word 0x00000000

C_hook:

Now to compile the C code it's a tiny bit more complex. DevKitARM has this bad habit of assuming that if we're compiling something that's C based that we're going to want it to be a full on GBA executable, which is not the case for us. What we want is a bare-bones C->binary executable that we can insert into the ROM with ease. Admittedly, it's not near as easy as compiling ASM, but with some compilation scripts and a Java JAR we can make it dead simple.

The first issue at hand is that if we tell DevKitARM's linker to turn our C object into a workable file for objcopy, it auto-links several built-in apis and several other things. Since we're going to be hacking this into a ROM, having all of those APIs will start to increase the size of our routine drastically and make it more difficult to return from our routine back to the bootloader. So instead, we provide our own linker file called linker.lsc.
Code:
OUTPUT_ARCH(arm)
 
MEMORY {
 
        rom     : ORIGIN = 0x08790058, LENGTH = 32M
        ewram   : ORIGIN = 0x02000000, LENGTH = 4M - 4k
}
 
 
SECTIONS {
        .text : {
               
                FILL (0xABCD)
               
                __text_start = . ;
                *(.init)
                *(.text)
                *(.ctors)
                *(.dtors)
                *(.rodata)
                *(.fini)
                *(COMMON)
                __text_end  = . ;
               
                __bss_start__ = . ;
                *(.bss)
                __bss_end__ = . ;
        _end = __bss_end__ ;
        __end__ = __bss_end__ ;
        } >rom = 0xff
}

What this file does it it tells linker two things: Where is our executable based, and how do we want our executable formatted. So for example, let's say we're inserting this routine at 0x790000. Since the bootloader takes up 0x58 bytes, we want the linker to start all of the pointers from 0x08790058 (08 is the beginning of the ROM in the GBA's memory).

Installing DevKitPro
OK, so now that we know how to compile, we're going to download the tools to do so. DevKitARM is a package inside of the mega DevKitPro SDK, which you can download here if your a Windows user. If your a Linux or Mac user, I trust that you can figure out how to install it on your own. Be patient, it can take quite a while to install. If you want to speed it up, you can untick the DevKitPSP and DevKitPPC toolkits. the important thing is that you have the DevKitARM toolkit since that's what we're going to be working with in this tutorial.

Once you have that installed, download IntroTemplate.zip from my Dropbox and extract the files.


A Few Notes about the Emerald Port
Thanks to diegoisawesome and I, the existing codebase for my intro has been ported to Emerald. However, there are a few key differences:

On Emerald, a bootloader isn't actually required. However, specific functions like the fadescreen are required to be exported to an ASM routine due to a bug in DevKitARM which causes register r3 to be overwritten with the offset to the routine your going to. So instead, compile the bootloader and insert it separate from your main routine and take note of the address for later in this tutorial. As for the C, just compile your code and insert it and place the pointer (+1) at 0x16CE78. The difference between the FireRed code and the Emerald port is actually nearly the same and it was designed this way so as to keep code portable between games. If there is an important difference though, I'll have a little spoiler pointing this out.


Now, go into the folder for the desired version, be it Fire Red or Emerald. First assemble the bootloader.asm using HackMew's batch script so that you get the bootloader.bin file. Next, double click the file called compile.bat, check to see if any errors appeared (which hopefully won't happen) and congrats! Your coding setup is now complete!

Now it's time to test our code out. Open bootloader.bin, intro.bin, and your ROM in your favorite hex editor. Now if you didn't change the offsets in useful.h and linker.lsc, you might want to do that now. Just open linker.lsc and edit the line that says rom : ORIGIN = 0x08790058, LENGTH = 32M to say rom : ORIGIN = 0x08<freespace+0x58>, LENGTH = 32M. Now open useful.h and find the line that has this offset: 0x08790025 (0x08790001 for Emerald) and change it to be 0x08<freespace+25> (or just freespace + 1 for Emerald).

Once you have that fixed, recompile and insert your bootloader into the offset you specified earlier, or if you didn't edit the files, just insert it at 0x790000. Now copy the contents from intro.bin and place it directly after the last byte of the bootloader. If your inserting this on Emerald, take note of this address as it will be needed. Now to hack in your routine, just place the reversed pointer to your bootloader (+1) at 0x0EC5D0. For Emerald, insert the pointer to your C code (+1), not the bootloader, at 0x16CE78.

Now save and open your ROM. do you see a little Quagsire walking across your screen? Congrats! You just replaced the intro! Now press A and your game should be taken to the title screen.


One Last Note Before Coding

All of the files in the ZIP were written in a Linux text editor, meaning that they use the Linux line ending format. This will cause it to look like there are no newlines in NotePad. To solve this, either use WordPad or download NotePad++ which has excellent syntax highlighting to help you keep organized while you code.


Making teh Codes

Still coming soon...

Resources and More
If your looking for some more info on how to do raw GBA ASM, I'd recommend these few documents:

JPAN's Thumb Tutorial Doc
A Bit of ASM by thethethethe (can't find at the moment, I'll try to find it on the web archive)
HackMew's Knowledge
GBATek
Patater's GBA ASM Tutorial
 
Last edited:

GoGoJJTech

(☞゚ヮ゚)☞ http://GoGoJJTech.com ☜(゚ヮ゚☜)
2,475
Posts
11
Years
Great! I was asking Jambo not long ago how I could do something like this. So with this knowledge, we could basically do something like DP's intro?
 

Shiny Quagsire

I'm Still Alive, Elsewhere
697
Posts
14
Years
Great! I was asking Jambo not long ago how I could do something like this. So with this knowledge, we could basically do something like DP's intro?

Yes, it would be possible, However, you would either have to split scenes into different callbacks or find a way around the distance limit for branching and linking.. I myself am currently looking for a way to write most of this in C as opposed to ASM, which would provide a much easier method of programming this. However, doing so it a bit difficult since ASM is much easier to hack into ROMs since C is meant to be for more standalone purposes.
 

GoGoJJTech

(☞゚ヮ゚)☞ http://GoGoJJTech.com ☜(゚ヮ゚☜)
2,475
Posts
11
Years
Well, the next community project could be to create intros according to each region and make patches. So a GS intro, a C intro, and DP intro, a BW intro. Something to get us to know each-other better.
 

Shiny Quagsire

I'm Still Alive, Elsewhere
697
Posts
14
Years
So you know how everyone always said that having a completely custom intro was impossible? Well, not anymore. :)


That's right, the entire Crystal intro running on top of the GBA. Still don't believe? I have the entire thing open sourced under GPLv3 on my GitHub, and this intro will also be featured in diegoisawesome's CrystalDust.

As such, I updated the thread to include instructions on how to compile a simple template intro, (which is again released under GPLv3, meaning that anything based on is is required to be open sourced), and also how it all works.
 

Gamer2020

Accept no Imitations!
1,062
Posts
15
Years
Very good. This is very impressive.

Looking through the thread I see nothing about music. I might of missed it and can't view the videos because I currently have to use proxies to get on but are you able to play music with the intro?

*Edit* I was finally able to download the code from the dropbox. I see that there are functions for sound and many other things.

Why did you put the functions in useful.h? Wouldn't they be better in a .c file?

*edit2*

Aside from some small things this is pretty good. I'll bet you can even use Tonc with this.

You should read this.
http://www.coranac.com/tonc/text/bitmaps.htm#sec-data

Especially "5.4.3. #including code or data considered harmful".
 
Last edited:
28
Posts
15
Years
  • Seen Jan 20, 2019
just fyi, you can also call functions already built into the game from your c/c++ files using a symbols file. i'm looking at useful.h and it looks like you're trying to call functions that are built into gamefreak's codebase. you can do that much more easily using the symbols file and declaring the functions in a header.

also, since i'm here, you can call C++ functions from assembly, but you have to call the mangled version of the name, not the undecorated version. if you call the undecorated version, it will pop an error as an unknown symbol/undefined function/whatever. something to keep in mind if someone decides to use c++ instead of straight C.

also, gamer2020 has a good point. you should either:

-convert the functions to static inlines
-throw them into their own source file with a new header
-create a symbols master file and do it that way

the third way would be the most ideal.

e: here's how:

http://pastebin.com/x0jtqF9H

after you do that, you can call getPkmStat and setPkmStat in your own code and they will work normally.


e2:

another fyi to shiny quagsire and everyone else thinking about using this:

you don't have to use the keyword __asm. you can just use asm. and you only have to use it once. like so:

ex.

Code:
void fadeScreenFast()
{
	__asm("mov r0, #0x1");
	__asm("mov r1, #0x0");
	int (*func)(void) = (int (*)(void))0x0807A819;
	int x = func();
}

void fadeScreenFast()
{
	   asm("mov r0, #0x1\n"
	          "mov r1, #0x0");
	int (*func)(void) = (int (*)(void))0x0807A819;
	int x = func();
}

though, that function itself should be built in via a symbol file and some inlines, but the method is useful.
 
Last edited:

Shiny Quagsire

I'm Still Alive, Elsewhere
697
Posts
14
Years
Very good. This is very impressive.

Looking through the thread I see nothing about music. I might of missed it and can't view the videos because I currently have to use proxies to get on but are you able to play music with the intro?

*Edit* I was finally able to download the code from the dropbox. I see that there are functions for sound and many other things.

Why did you put the functions in useful.h? Wouldn't they be better in a .c file?

*edit2*

Aside from some small things this is pretty good. I'll bet you can even use Tonc with this.

You should read this.
http://www.coranac.com/tonc/text/bitmaps.htm#sec-data

Especially "5.4.3. #including code or data considered harmful".
Yes, there's music and sound effects. Tonc would most likely work too, but my only concern is space since the C code can get pretty large compared to ASM.

Most of the reason for what I do is because I'm really not a C buff. Like, at all. I primarily do Java and ASM, so naturally I'm still learning C and I just recently learned how to do makefiles. And I have looked over Tonc's tutorials (I even read that specific phrase) but the only reason I haven't done so is simply because I don't know how to. I do want to do that though so that I can prevent it from recompiling the same file even when it isn't needed, and make has been giving me issues in reguards to #includes.

just fyi, you can also call functions already built into the game from your c/c++ files using a symbols file. i'm looking at useful.h and it looks like you're trying to call functions that are built into gamefreak's codebase. you can do that much more easily using the symbols file and declaring the functions in a header.

also, since i'm here, you can call C++ functions from assembly, but you have to call the mangled version of the name, not the undecorated version. if you call the undecorated version, it will pop an error as an unknown symbol/undefined function/whatever. something to keep in mind if someone decides to use c++ instead of straight C.

also, gamer2020 has a good point. you should either:

-convert the functions to static inlines
-throw them into their own source file with a new header
-create a symbols master file and do it that way

the third way would be the most ideal.

e: here's how:

http://pastebin.com/x0jtqF9H

after you do that, you can call getPkmStat and setPkmStat in your own code and they will work normally.


e2:

another fyi to shiny quagsire and everyone else thinking about using this:

you don't have to use the keyword __asm. you can just use asm. and you only have to use it once. like so:

ex.

Code:
void fadeScreenFast()
{
	__asm("mov r0, #0x1");
	__asm("mov r1, #0x0");
	int (*func)(void) = (int (*)(void))0x0807A819;
	int x = func();
}

void fadeScreenFast()
{
	   asm("mov r0, #0x1\n"
	          "mov r1, #0x0");
	int (*func)(void) = (int (*)(void))0x0807A819;
	int x = func();
}

though, that function itself should be built in via a symbol file and some inlines, but the method is useful.

Note taken on the asm thing. I haven't actually seen it done that way as of yet, but I'm open to improvement on my C skills. As for C++, C has been working for me so far and I haven't found the need for any C++ specific additions as of yet. As for the symbols file, I'll probably start doing that since I've run into some issues with my current methods, specifically always having the fourth arguments (r3) overwritten with the location of the function since the compiler just ldr's the function and bl's to a bx r3, so an external symbols file would save a lot of pain and would also completely remove the bootloader from Emerald and maybe Fire Red.
 

Full Metal

C(++) Developer.
810
Posts
16
Years
Would somebody show me what compiling / assembling / linking using a symbol file would look like? I looked at the pastebin and it just looks like a text file describing function names to their locations in the ROM ( which, makes sense ) but I haven't a clue how I would compile that as I've never really heard of doing something like this before.

no I have not looked at the code in github so if this is in there just tell me and I'll go look at the makefile
 
28
Posts
15
Years
  • Seen Jan 20, 2019
Yes, there's music and sound effects. Tonc would most likely work too, but my only concern is space since the C code can get pretty large.... etc


one more thing. let's say you have a struct that's part of the game that you need to use that's very large and complex with a bunch of members, but you never have to modify it yourself. something like this:

typedef struct graphics_struct {

u32 data;
u32 more_data;

etc etc...

} graphics_struct;

bool im_a_function(graphics_struct* gx);


so im_a_function accepts the struct and modifies it, but you never have to. you don't even have to know what everything in it does, just the size of the struct. since modifying an array is the same thing as modifying a struct in assembly, just offsetted loads and stores, you can do this:

typedef u8 graphics_struct[0x64];

graphics_struct gfx;

bool result = im_a_function(gfx);

and if you need to modify certain members, just write some small functions that take a pointer to the "struct" using the asm keyword in the function to load and store at the offsets you need.

think of it like file manipulation using the crt. you would do something like this:

FILE* fp

fp = fopen(fname, "rb+");

and then you could use fp with the other file manipulation functions, but you never actually modify fp yourself, if that makes sense. same deal with the example above. and if you did need to modify it and the functions weren't built into the game, you could go a step farther and write some small C functions using the asm keyword to get the job done.


anyway, i'm just mentioning it because i've done this a few times in my code for white 2 and it's been helpful. i've only ever used it for things i don't have to modify, like osthreads, fsfile, etc, but since the asm keyword is easy to use, you can get away with it.
 
Last edited:

Gamer2020

Accept no Imitations!
1,062
Posts
15
Years
I think that if you were to make a library it would help with the space thing. I'm pretty sure that with a library only the code that is actually called gets included in the final product.

Also with Tonc things are done a little different and some things are labeled different (in a better way.) It may just be a matter of preference in the end.
 
28
Posts
15
Years
  • Seen Jan 20, 2019
fyi shiny quagsire, i've been experimenting with the linker and symbol files and i've found that the best way to use THUMB calls with a symbol file involves adding an extra bit to the makefile. basically, what happens is that all the symbols in the symbol file are assumed to be ARM functions, so the branching ends up a little bit messed up when you try to use it from THUMB code. i didn't notice this initially because my original code was ARM. however, if you enable long calls in the compiler flags, it will switch over to using __call_from_r3, __call_from_r4, etc as veneers straight to the expression provided for the symbol. this ensures that your THUMB symbols will be honored(at a VERY slight performance penalty, not even something to worry about) so long as you make sure each of them have the +1 for the address.(i.e. a function @ 800353C would be listed in the symbol file as being @ 800353D).

to add the compiler flag, you simply do this:

Code:
CFLAGS	:=	-mthumb -mthumb-interwork -g -Wall -O2\
 		-march=armv4t -mtune=arm7tdmi -fomit-frame-pointer\
		-ffast-math -mlong-calls\
		$(ARCH)

the only change there is "-mlong-calls". add that flag and you're all set. you can set .text wherever you want, put code anywhere, build functions in ARM that can be memcpy-ed to iwram and run them from there, etc. without worrying about the function calls.

also, i was rereading my posts from last week, and it seems like i sort of implied that you can't use any functions from libnds/libgba. just what's built into the rom. that's not true. if you're using libgba's header, you can call libgba functions and they'll be tacked onto your binary. you may not have any luck with the newlib/libc functions, but you can still use their headers for macros and stuff.
 
Last edited:

Shiny Quagsire

I'm Still Alive, Elsewhere
697
Posts
14
Years
fyi shiny quagsire, i've been experimenting with the linker and symbol files and i've found that the best way to use THUMB calls with a symbol file involves adding an extra bit to the makefile. basically, what happens is that all the symbols in the symbol file are assumed to be ARM functions, so the branching ends up a little bit messed up when you try to use it from THUMB code. i didn't notice this initially because my original code was ARM. however, if you enable long calls in the compiler flags, it will switch over to using __call_from_r3, __call_from_r4, etc as veneers straight to the expression provided for the symbol. this ensures that your THUMB symbols will be honored(at a VERY slight performance penalty, not even something to worry about) so long as you make sure each of them have the +1 for the address.(i.e. a function @ 800353C would be listed in the symbol file as being @ 800353D).

to add the compiler flag, you simply do this:

Code:
CFLAGS	:=	-mthumb -mthumb-interwork -g -Wall -O2\
 		-march=armv4t -mtune=arm7tdmi -fomit-frame-pointer\
		-ffast-math -mlong-calls\
		$(ARCH)

the only change there is "-mlong-calls". add that flag and you're all set. you can set .text wherever you want, put code anywhere, build functions in ARM that can be memcpy-ed to iwram and run them from there, etc. without worrying about the function calls.

also, i was rereading my posts from last week, and it seems like i sort of implied that you can't use any functions from libnds/libgba. just what's built into the rom. that's not true. if you're using libgba's header, you can call libgba functions and they'll be tacked onto your binary. you may not have any luck with the newlib/libc functions, but you can still use their headers for macros and stuff.

That will definately help, I've been having so many issues with that particular quirk it's not even funny, so having that functionality will greatly reduce the pain of calling functions with large amounts of variables and will even remove the "bootloader" for Emerald. Thanks!
 
28
Posts
15
Years
  • Seen Jan 20, 2019
also, one other thing. instead of having to edit the linker script each time you want to compile for a different address, you can do this:

Code:
make CODEADDR=0x8xxxxxx

this way you only have to make 1 linker script and never touch it again. i have a batch file that's nothing but

Code:
make CODEADDR=0x23A8B10
pause

that i use for testing my libpkm and it works quite nicely.
 
Last edited:

Mystelex

Guest
0
Posts
I want to insert the Pokémon Gold/Silver intro into Firered. How to make the code ?
 

Mystelex

Guest
0
Posts
.... It's already all explained in the first post
Everything is there
There's even source to the one he used for the video

Yeah , that's fine. He has mentioned the codes in the thread. But how to code a custom intro ? How did you code Platinum's intro for Platinum Red ?
 

Touched

Resident ASMAGICIAN
625
Posts
9
Years
  • Age 122
  • Seen Feb 1, 2018
Yeah , that's fine. He has mentioned the codes in the thread. But how to code a custom intro ? How did you code Platinum's intro for Platinum Red ?

He used C, just like shiny did. You need a fair understanding of how the game's engine works (which means you need to understand ASM) and you need to be able to code in C. The instructions given here are sufficiently clear if you fulfil the above the criteria.
 
Back
Top