GameBoy Advance Multiboot
Boot up a GameBoy Advance though it's serial port
The main purpose of this program is to load a program onto the GameBoy with out the need for a flash cartridge.
I have a couple of gba multiboot files that will work with this setup on my web site. I originally did this with a PIC24.

// mbed GBA Loader - Boot up a GameBoy Advance using Multiboot (no cart req.)
//
// Ken Kaarvik kkaarvik@yahoo.com
// Nov 13, 2010
//
// mbed gba serial port
// 1-0V 6-0V
// p5-mosi 3-SI
// p6-miso 2-SO
// p7-sck 5-SC
// p8-input 1-3V3
//
// p15-analogIn 0-3V3 test voltage pot
// p16-analogIn 0-3V3 test voltage pot
//
// note: the GBA does not power the mbed
//
// The GBA file that you wish to load into the GBA is stored on the mbed's local file system.
// (Just drag and drop it onto the drive where mbed is located.)
// The GBA can be multibooted with a maximum file size of 256kB (the mbed shows up on my
// computer as a flash drive with 2MB of memory, room for several GBA files!)
//
// Apply power to the mbed (or reset) before turning on the GBA.
//
#include "mbed.h"
Serial pc(USBTX, USBRX); //debug info - see raw data being transferred back and forth as GBA is booting
SPI spi(p5, p6, p7); // mosi, miso, sclk
LocalFileSystem local("local");
DigitalIn gba_present(p8);
DigitalOut myled1(LED1); //used for my demo program (volt4.gba)
DigitalOut myled2(LED2); //used for my demo program (volt4.gba)
DigitalOut myled3(LED3); //used for my demo program (volt4.gba)
DigitalOut myled4(LED4); //used for my demo program (volt4.gba)
AnalogIn voltmeter1(p15); //used for my demo program (volt4.gba)
AnalogIn voltmeter2(p16); //used for my demo program (volt4.gba)
unsigned long read_from_gba;
//unsigned long test_counter;
long writeSPI32bits(long write32)
{
pc.printf("0x%08x ",write32);
long read32 = (spi.write(write32>>16))<<16;
read32 = (spi.write(write32))|read32;
pc.printf("0x%08x ",read32);
return read32;
}
long writeSPI32bits_nodebug(long write32)
{
long read32 = (spi.write(write32>>16))<<16;
read32 = (spi.write(write32))|read32;
return read32;
}
int main()
{
// Setup the spi for 8 bit data, high steady state clock,
// second edge capture, with a 100 kHz clock rate
spi.format(16,3);
spi.frequency(100000);
pc.printf("\n\n\r.....GBA Multiboot Hack......\n\n\r");
if (gba_present)
pc.printf(".....Please turn off GBA.....\n\r");
while(gba_present);
wait(0.2);
if(!gba_present)
pc.printf(".....Please turn on GBA......\n\r");
while(!gba_present);
wait(0.2);
pc.printf(".....GBA power up detected!..\n\r");
FILE *fp = fopen("/local/volt4.gba", "rb"); //*****change .gba file here*****
pc.printf(".....Opening GBA file readonly\r\n");
fseek(fp, 0L, SEEK_END); //get *.gba file length
long gba_file_length= ftell(fp);
gba_file_length = (gba_file_length+0x0f)&0xfffffff0; //align length to xfer to 16
fseek(fp, 0L, SEEK_SET);
pc.printf(".....GBA file length 0x%08x\r\n\n",gba_file_length);
pc.printf("MBED(mstr) GBA(slave) \r\n\n");
while(read_from_gba!=0x72026202)
{
wait(0.01);
read_from_gba = writeSPI32bits(0x00006202);
pc.printf(" ;Looking for GBA\r\n");
}
read_from_gba = writeSPI32bits(0x00006202);
pc.printf(" ;Found GBA\r\n");
read_from_gba = writeSPI32bits(0x00006102);
pc.printf(" ;Recognition ok\r\n");
int i;
for(int Counter=0;Counter<=0x5f;Counter++)
{
i = getc(fp); //Read in 16 bits of .gba file
i = getc(fp)<<8|i; //Read in 16 bits of .gba file
read_from_gba = writeSPI32bits_nodebug(0x0000ffff&i);
// pc.printf(" ;send header a\r\n");
}
read_from_gba = writeSPI32bits(0x00006200);
pc.printf(" ;Transfer of header data complete\r\n");
read_from_gba = writeSPI32bits(0x00006202);
pc.printf(" ;Exchange master/slave info again\r\n");
read_from_gba = writeSPI32bits(0x000063d1);
pc.printf(" ;Send palette data\r\n");
read_from_gba = writeSPI32bits(0x000063d1);
pc.printf(" ;Send palette data, receive 0x73hh****\r\n");
long m = ((read_from_gba&0x00ff0000)>>8)+0xffff00d1;
long hh = ((read_from_gba&0x00ff0000)>>16)+0xf;
writeSPI32bits((((read_from_gba>>16)+0x0000000f)&0xff)|0x00006400);
pc.printf(" ;Send handshake data\r\n");
read_from_gba = writeSPI32bits((gba_file_length-0x190)/4);
pc.printf(" ;Send length info, receive seed 0x**cc****\r\n");
long c = 0x0000c387;
long f = ((((read_from_gba&0x00ff0000)>>8)+hh)+0x00)|0xffff0000;
pc.printf(" ;Send encrypted data (takes too long to show it all!)\r\n");
unsigned int gba_file_location = 0xc0;
while(gba_file_location>1)^0x0000c37b;
else
c = c>>1;
gba_data = gba_data>>1;
}
m = (0x6f646573*m)+1;
writeSPI32bits_nodebug(gba_data2^((~(0x02000000+gba_file_location))+1)^m^0x43202f2f);//This line or next two
// writeSPI32bits(gba_data2^((~(0x02000000+gba_file_location))+1)^m^0x43202f2f); //*****Uncomment two line to see all data being transfered*****
// pc.printf(" ;\n\r"); //*****Uncomment two line to see all data being transfered*****
gba_file_location=gba_file_location+4;
}
for(int bit=0;bit<32;bit++)
{
if((c^f)&0x01)
c =(c>>1)^0x0000c37b;
else
c = c>>1;
f = f>>1;
}
while (writeSPI32bits(0x00000065)!=0x00750065)
{
pc.printf(" ;Wait for GBA to respond with CRC\n\r");
}
pc.printf(" ;GBA ready with CRC\n\r");
writeSPI32bits(0x00000066);
pc.printf(" ;Let's exchange CRC!\n\r");
writeSPI32bits(c);
pc.printf(" ;CRC ...hope they match!\n\r");
pc.printf(" ;All done!\n\r\n");
fclose(fp); //****Done with multiboot********************************************************
//****Following is code to talk to GBA running my custom program (volt4.gba)*****
while(1) //read in analog values on p15 and p16, only use 9 bits from both, pack up and send to GBA
{
read_from_gba = writeSPI32bits((voltmeter1.read_u16()>>7)|((voltmeter2.read_u16()&0xff80)<<2));
pc.printf("\r");
read_from_gba =(~read_from_gba)&0x3ff;
myled1 = (read_from_gba & 0x1); //turn on led1 when "A" button on GBA is pressed
myled2 = (read_from_gba & 0x2); //B
myled3 = (read_from_gba & 0x4); //Select
myled4 = (read_from_gba & 0x8); //Start
}
}
4 comments
You need to log in to post a comment

Awesome! I was looking at your GBA source files and was wondering if its possible to make them in C++ because assembly just shoots way over my head