gbadev.org forum archive

This is a read-only mirror of the content originally found on forum.gbadev.org (now offline), salvaged from Wayback machine copies. A new forum can be found here.

C/C++ > Undefined reference to CpuFastSet

#79780 - phoenixj91 - Sat Apr 15, 2006 11:31 pm

I'm trying out the code from Day 4 of the PERN project. I went through and corrected the names of all the register constants, which were almost all incorrect in the tutorial (BGCOLOR_256 instead of BGCOLOR256, for instance). I got everything except for CpuFastSet. Here's what returns when I compile:
Code:

>build.bat
main.o(.text+0xba): In function `main':
C:\Projects\Chronofox/main.c:14: undefined reference to `CpuFastSet'
main.o(.text+0xc6):C:\Projects\Chronofox/main.c:15: undefined reference to `CpuFastSet'
collect2: ld returned 1 exit status
arm-elf-objcopy: 'Chronofox.elf': No such file
ROM fixed!
Could Not Find C:\Projects\Chronofox\Chronofox.elf
Chronofox compiled successfuly
>Exit code: 1


Here's my code (truncated to the parts that matter):
Code:

//Main program loop
#include "gba.h"
#include "functions.h"

int main(){ //Begin program
   initoam(); //Clear sprite memory
   SetMode(MODE_0 | BG2_ENABLE | OBJ_ENABLE | OBJ_MAP_1D); //Set screenmode

   u16*  vrammap = (u16*)SCREEN_BASE_BLOCK(31);
   u16*  vramtiles = (u16*)MAP_BASE_BLOCK(0);
   REG_BG2CNT= BG_COLOR_256 | ROTBG_SIZE_128x128 | WRAPAROUND | (31<<SCREEN_SHIFT) | (0 << CHAR_SHIFT);
   CpuFastSet(vrammap,testmap,16*16/4);
   CpuFastSet(vramtiles,checker,64/4); //testmap and checker are defined in functions.h

        while(1){}
}


I checked it all out and gba_bios.h is getting included in the project and everything, but the function is still not recognized. Do I have to include an external assembler file in my project or something?
Sorry for being clueless ;_;

#79806 - tepples - Sun Apr 16, 2006 1:51 am

Are you remembering to link in libgba (use option -lgba ) when you build the .elf file? Please list build.bat.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#79808 - phoenixj91 - Sun Apr 16, 2006 1:55 am

build.bat:
Code:
@echo off
REM just add  .c file and  .o file to the next two lines

set CFILES=main.c
set OFILES=main.o
set STATICO=spriteData.o spritePalette.o

set GAME=Chronofox
set SPECS=gba_mb.specs

set DEVDIR=C:\Devkitarm

PATH=%DEVDIR%\bin;%path%

REM set our paths so the linker knows were to look for the libs
set LIBDIR= %DEVDIR%\arm-elf\lib\interwork
set LIBDIR2= %DEVDIR%\libgba\lib

REM set our include directories so the compiler can find our include files
set INCDIR= %DEVDIR%\arm-elf\include
set INCDIR2= %DEVDIR%\include\gba

REM the compiler and linker flags
set CFLAGS= -I.  -I%INCDIR% -I%INCDIR2% -c -g -O2 -Wall -mcpu=arm7tdmi -mtune=arm7tdmi -fomit-frame-pointer -ffast-math -mthumb -mthumb-interwork

set LDFLAGS=  -mthumb -mthumb-interwork -specs=%SPECS% -L%LIBDIR% -L%LIBDIR2% 

REM Splice and convert the sprites
pcx2sprite .\pxart\crfoxsheet1.pcx -i:sprite -w:16 -h:32

REM Compile the cfiles
arm-elf-gcc  %CFILES% %CFLAGS%

REM link the o files
arm-elf-gcc -o %GAME%.elf  %STATICO% %OFILES% %LDFLAGS%

REM gcc produces .elf exicutables...objcopy to .gba
arm-elf-objcopy -v -O binary %game%.elf %game%.gba

gbafix %game%.gba

REM remove all the ofiles
del %OFILES%
del %game%.elf

echo %GAME% compiled successfuly
C:\projects\gba\vba.exe %GAME%.gba

#79809 - phoenixj91 - Sun Apr 16, 2006 1:58 am

=-o
It worked, thanks a bunch tepples!!

#79895 - phoenixj91 - Sun Apr 16, 2006 11:33 pm

New problem:
CpuFastSet doesn't do anything. I only began to get tiles show up after using a for loop instead. Even then, I still had trouble. Here's my code:
Code:
   SetMode(MODE_0 | BG2_ENABLE | OBJ_ENABLE | OBJ_MAP_1D); //Set screenmode

   u16*  vrammap = (u16*)SCREEN_BASE_BLOCK(31);
   u16*  vramtiles = (u16*)MAP_BASE_BLOCK(0);
   REG_BG2CNT= BG_COLOR_256 | ROTBG_SIZE_128x128 | WRAPAROUND | (31<<SCREEN_SHIFT) | (0 << CHAR_SHIFT);

   //CpuFastSet(vrammap,testmap,sizeof(testmap));
   //CpuFastSet(vramtiles,checker,64/4);
   //CpuFastSet(BGPaletteMem,bgpalettecopy,sizeof(bgpalettecopy));
   int t;
   for(t=0;t<3;t++){BGPaletteMem[t]=bgpalettecopy[t];}
   for(t=0;t<256;t++){vrammap[t]=testmap[t];}
   for(t=0;t<64;t++){vramtiles[t]=checker[t];}

"testmap" is basicly a 256 char array consisting entirely of 0s
"bgpalettecopy" is a 3 int long array which looks like this:
Code:
unsigned int bgpalettecopy[3]={RGB16(31,0,0),RGB16(31,31,31),RGB16(0,0,0)};

"checker" is a array of 64 chars forming a checkerboard pattern that should look like this:
[Images not permitted - Click here to view it]
However, this all ends up looking like this:
[Images not permitted - Click here to view it]
The palette does get loaded successfuly and the map seems to as well (through VBA's map and palette viewer)
What am I doing wrong?

#79899 - Cearn - Mon Apr 17, 2006 12:18 am

phoenixj91 wrote:
New problem:
CpuFastSet doesn't do anything. I only began to get tiles show up after using a for loop instead. Even then, I still had trouble. Here's my code:
Code:
   SetMode(MODE_0 | BG2_ENABLE | OBJ_ENABLE | OBJ_MAP_1D); //Set screenmode

   u16*  vrammap = (u16*)SCREEN_BASE_BLOCK(31);
   u16*  vramtiles = (u16*)MAP_BASE_BLOCK(0);
   REG_BG2CNT= BG_COLOR_256 | ROTBG_SIZE_128x128 | WRAPAROUND | (31<<SCREEN_SHIFT) | (0 << CHAR_SHIFT);

   //CpuFastSet(vrammap,testmap,sizeof(testmap));
   //CpuFastSet(vramtiles,checker,64/4);
   //CpuFastSet(BGPaletteMem,bgpalettecopy,sizeof(bgpalettecopy));

Actually, CpuFastSet probably does work, the problem is that your source and destination addresses are swapped.
Code:
extern void CpuFastSet(void *source, void *dest, u32 mode);

Also, the size should be in words, so you need to divide the sizeof() things by 4. Oh, something you should know about sizeof().

You're in mode 0, but setting up REG_BG2CNT as if it were an affine map. What you're actually creating is a 256x256 pixel regular map.

phoenixj91 wrote:

Code:
   int t;
   for(t=0;t<3;t++){BGPaletteMem[t]=bgpalettecopy[t];}
   for(t=0;t<256;t++){vrammap[t]=testmap[t];}
   for(t=0;t<64;t++){vramtiles[t]=checker[t];}

"testmap" is basically a 256 char array consisting entirely of 0s
"bgpalettecopy" is a 3 int long array which looks like this:
Code:
unsigned int bgpalettecopy[3]={RGB16(31,0,0),RGB16(31,31,31),RGB16(0,0,0)};

What am I doing wrong?


bgpalettecopy is a u32 array, whereas BGPaletteMem is an u16 array. Fine if you're using a loop for copying, not fine if you're using anything else.

testmap may be a char array, but as far as I can see vrammap isn't (that's u16[]). Fine if you're using zeroes, but not for any real data. Also, 256 is not enough to fill the whole map (because it isn't an affine bg).

checker may be a char array, but as far as I can see vramtiles isn't (that's u16[]). Fine if you're using zeroes, but not for any real data. Which is this case means that the 0x01's and 0x02's of the charmap will be converted to halfwords and end up as 0x0001's and 0x0002's. Which will be interpreted as 01, 00, 02, 00 by the renderer.

#79907 - phoenixj91 - Mon Apr 17, 2006 1:16 am

Cearn wrote:

Actually, CpuFastSet probably does work, the problem is that your source and destination addresses are swapped.

Right you are. That was stupid on my part XD
Cearn wrote:

Also, the size should be in words, so you need to divide the sizeof() things by 4.

Done:
Code:
   CpuFastSet(testmap,vrammap,sizeof(testmap)/4);
   CpuFastSet(checker,vramtiles,sizeof(vramtiles)/4);
   CpuFastSet(bgpalettecopy,BGPaletteMem,sizeof(bgpalettecopy)/4);

Cearn wrote:

You're in mode 0, but setting up REG_BG2CNT as if it were an affine map. What you're actually creating is a 256x256 pixel regular map.

So, I would replace the register flag ROTBG_SIZE_128x128 with TEXTBG_SIZE_256x256? I did so and it didn't change much
Cearn wrote:

bgpalettecopy is a u32 array, whereas BGPaletteMem is an u16 array. Fine if you're using a loop for copying, not fine if you're using anything else.

testmap may be a char array, but as far as I can see vrammap isn't (that's u16[]). Fine if you're using zeroes, but not for any real data. Also, 256 is not enough to fill the whole map (because it isn't an affine bg).

checker may be a char array, but as far as I can see vramtiles isn't (that's u16[]). Fine if you're using zeroes, but not for any real data. Which is this case means that the 0x01's and 0x02's of the charmap will be converted to halfwords and end up as 0x0001's and 0x0002's. Which will be interpreted as 01, 00, 02, 00 by the renderer.

I just fixed all the datatypes.

Something looked definatley wrong, so I changed checker to an array of 64 u16s propagated entirely with 1s - a solid white square. This was the result:
[Images not permitted - Click here to view it]

#79947 - Cearn - Mon Apr 17, 2006 2:11 pm

phoenixj91 wrote:
Cearn wrote:
You're in mode 0, but setting up REG_BG2CNT as if it were an affine map. What you're actually creating is a 256x256 pixel regular map.

So, I would replace the register flag ROTBG_SIZE_128x128 with TEXTBG_SIZE_256x256? I did so and it didn't change much

No it wouldn't, because they're the same thing :P
ROTBG_SIZE_128x128 and TEXTBG_SIZE_256x256 are both defined as 0, what makes a bg text or affine is the video mode. You'd need either mode 1 or 2 for affine maps.

phoenixj91 wrote:
Something looked definatley wrong, so I changed checker to an array of 64 u16s propagated entirely with 1s - a solid white square. This was the result:
[Images not permitted - Click here to view it]

I think you may be missing the point. If you've just changed the type, you have something like this, right?
Code:
const u16 checker[]= { 1, 1, 1, 1 ... };

The point is that you'll still have 0x0001, 0x0001 going into the tiles, what you need is any pattern that'll show up in the memory viewer as "01 01 01 01", not "01 00 01 00", which is what you have now.

The problem with the earlier loop-copy was that the destination was in halfwords, but the source in bytes. You need to take a step back and try to understand how any given array would actually appear in memory. Once that's done you'll see what you have to do. The VBA memory viewer can help with this.

A secondary problem is that the first pixel of your tile is still empty. This is probably because of a data-misalignment. CpuFastSet requires that the addresses are aligned to 4-byte boundaries.

tonc: on data.

#79950 - phoenixj91 - Mon Apr 17, 2006 4:02 pm

Cearn wrote:

A secondary problem is that the first pixel of your tile is still empty. This is probably because of a data-misalignment. CpuFastSet requires that the addresses are aligned to 4-byte boundaries.
tonc: on data.

Thanks for the link, my tile data looks better now:
Code:
__attribute__(( aligned(4) )) u16 checker[64]={
   0x0101,0x0101,0x0101,0x0101,0x0101,0x0101,0x0101,0x0101,
   0x0101,0x0101,0x0101,0x0101,0x0101,0x0101,0x0101,0x0101,
   0x0101,0x0101,0x0101,0x0101,0x0101,0x0101,0x0101,0x0101,
   0x0101,0x0101,0x0101,0x0101,0x0101,0x0101,0x0101,0x0101,
   0x0101,0x0101,0x0101,0x0101,0x0101,0x0101,0x0101,0x0101,
   0x0101,0x0101,0x0101,0x0101,0x0101,0x0101,0x0101,0x0101,
   0x0101,0x0101,0x0101,0x0101,0x0101,0x0101,0x0101,0x0101,
   0x0101,0x0101,0x0101,0x0101,0x0101,0x0101,0x0101,0x0101
};

Though the second half of the tile is still empty. I'll figure that out though.
[EDIT]
And again, thanks to your TONC tutorials, I realized I was using sizeof() to get the size of the pointer to VRAM and not my tile array "checker".
Spiffy little section on data management you've written there :-D !