/* Devkit Advance, multiboot, global variables, and malloc()
I've been having problems getting Devkit Advance (a GCC toolchain)
to make working multiboot binaries in some circumstances.
Three specific issues follow:
If I make a large uninitialized global variable, it increases the
size of the binary significantly.
If I make a multiboot program with a global variable in EWRAM, the
program won't run in an emulator nor on hardware.
If I call malloc() from a multiboot program, the memory allocated
overlaps the program's code and data.
*/
/*** begin smiley.c ***/
#include <stdlib.h>
/* excerpts from pin8gba.h, which uses variable names that
1. make sense to me and 2. aren't official so the big
N can't touch me */
typedef unsigned short u16;
struct BGPOINT
{
u16 x, y;
};
typedef u16 NAMETABLE[32][32];
#define RGB(r,g,b) ((r)|(g)<<5|(b)<<10)
#define PALRAM ((u16 *)0x05000000)
#define VRAM ((u16 *)0x06000000)
#define MAP ((NAMETABLE *)0x06000000)
#define LCDMODE (*(volatile u16 *)0x04000000)
#define LCDMODE_BLANK 0x0080
#define LCDMODE_BG0 0x0100
#define LCD_Y (*(volatile u16 *)0x04000006) /* 0-159: draw; 160-227
vblank */
#define BGCTRL ((volatile u16 *)0x04000008)
#define BGCTRL_PAT(m) ((m) << 2)
#define BGCTRL_16C 0x0000
#define BGCTRL_256C 0X0080
#define BGCTRL_NAME(m) ((m) << 8)
#define BGCTRL_H32 0x0000
#define BGCTRL_H64 0x4000
#define BGCTRL_V32 0x0000
#define BGCTRL_V64 0x8000
#define BGSCROLL ((volatile struct BGPOINT *)0x04000010)
#define IN_EWRAM __attribute__ ((section (".ewram")))
#define IN_IWRAM __attribute__ ((section (".iwram")))
#define CODE_IN_IWRAM __attribute__((section(".iwram"),long_call))
/*** Controls ***/
/* Comment out the following line to make a cartridge image
as opposed to a multiboot image. */
int __gba_multiboot;
/* Uncomment the following line to make a global variable
that adds 20 KB to the size of the binary. */
// char blah[20480] IN_IWRAM;
/* Uncomment the following line to make a global variable
that adds 20 KB to the size of the binary and does not
run when sent over multiboot. */
// char blah[20480] IN_EWRAM;
/*** Map data ***/
const unsigned short circle_data[16] =
{
0x07e0,0x1818,0x2004,0x4002,0x4002,0x8001,0x8001,0x8001,
0x8001,0x8001,0x8001,0x4002,0x4002,0x2004,0x1818,0x07e0
};
const unsigned short smiley_data[16] =
{
0x07e0,0x1818,0x2004,0x4002,0x4002,0x8c31,0x8c31,0x8001,
0x8001,0x8811,0x8421,0x43c2,0x4002,0x2004,0x1818,0x07e0
};
const unsigned short frowny_data[16] =
{
0x07e0,0x1818,0x2004,0x4002,0x4002,0x8c31,0x8c31,0x8001,
0x8001,0x83c1,0x8421,0x4812,0x4002,0x2004,0x1818,0x07e0
};
void draw_smiley(unsigned int nt, const unsigned short *img_data)
{
unsigned int x, y;
/* 1024 u16's in a map, 16 u16's in a 16-color tile;
therefore a map takes the same space as 64 tiles.
To save RAM, draw_smiley() uses tiles 62 and 63 to draw the
black and white blocks. */
unsigned int base_tile = (nt << 6) | 0x3e;
/* clear the map */
for(x = 0; x < 20*32; x++)
MAP[nt][0][x] = 0x3e3e;
/* set up tiles 62 and 63 to constant colors 0 and 1 */
for(x = 62*16; x < 63*16; x++)
MAP[nt][0][x] = 0x0000;
for(x = 63*16; x < 64*16; x++)
MAP[nt][0][x] = 0x1111;
/* draw map */
for(y = 0; y < 16; y++)
{
int shiftreg = img_data[y];
for(x = 0; x < 16; x++)
{
MAP[nt][y + 2][x + 7] = (shiftreg & 1) | base_tile;
shiftreg >>= 1;
}
}
}
/* helper function to display an integer in binary */
void display_int(unsigned int shiftreg, unsigned int y)
{
unsigned int bits;
for(bits = 29; bits > 0; bits--)
{
MAP[0][y][bits] = (shiftreg & 1) | 0x3e;
shiftreg >>= 1;
}
}
int does_malloc_work(void)
{
/* This allocates 40 KB of space and _should_ come out of EWRAM. */
unsigned char *foo = malloc(40960);
if(!foo)
return 0;
/* display pointer using 0 and 1 blocks */
display_int((unsigned int)foo, 19);
/* display address of this function
should display 0x0800xxxx for cart or 0x0200xxxx for multiboot
*/
display_int((unsigned int)does_malloc_work, 18);
free(foo);
return 1;
}
#define MAP_TO_USE 0
int main(void)
{
LCDMODE = LCDMODE_BLANK;
draw_smiley(MAP_TO_USE, smiley_data);
does_malloc_work();
BGSCROLL[0].x = 0;
BGSCROLL[0].y = 0;
BGCTRL[0] = BGCTRL_PAT(0) | BGCTRL_16C | BGCTRL_NAME(MAP_TO_USE) |
BGCTRL_H32 | BGCTRL_V32;
PALRAM[0] = RGB(0, 0, 24);
PALRAM[1] = RGB(31, 31, 28);
while(LCD_Y != 226);
LCDMODE = 0 | LCDMODE_BG0;
while(1) ;
}
/*** end smiley.c ***/
/* Conclusions
Apparently, what would go in the BSS section in a "normal" binary
goes into DATA in a Devkit Advance ROM.
The multiboot crt0.s doesn't set up the malloc() arena in EWRAM
properly. Has anybody been able to get Devkit Advance's malloc()
to work in multiboot?
*/