COOKIES

This site may be using cookies to melk you with your own data. I, ben0bi, am not the owner of this web service and I also do not maintain their servers. But the EU and the owner of this service think, that the user (me) has the responsibility to inform the consumer (you), that this website uses cookies. Again: I, ben0bi, NEVER use cookies. I am not responsible for the setup of this web service. I just present some information here and do not intend to spy on you for whatever reason ever. But (also again), I do not host this website nor do I maintain any servers related to this website nor do I benefit from using the cookies maintained from this service. I hereby give the responsibility for using cookies on blogspot back to the owners of blogspot.

Samstag, 29. August 2015

GameBoy Color: Hardware Modding

Like mentioned in this post here, my friend SneezyCerritus gets the best out of an old GameBoy Color on the hardware side. I wanted to load my homebrew GBC-modules so he ordered a cardridge with a microSD-slot. Then he had the idea to put that cardridge inside the GBC so we could either use games from the microSD slot (all there are ;) ) or use an original Gameboy-cardridge on the other side, without taking the microSD-cardridge out.

Also, he decided to put an accumulator pack and a microUSB-accumulator-load-slot into it.

WARNING: This project is freaking expensive and only for enthusiasts. It is a nice thing but it's very costly. I bet you can never sell it for the price below, which is:
--> more than 300 CHF and counting...

This is the device we are talking about, in exactly that color (but this images are stolen from the internet because we started making pictures after the start of modding.)


And here is an image of the back, for your consideration:


Here is what we got to build into the case:
http://opcoa.st/JGdT7

It's an "Everdrive GB V1.2"

Also he got a Li-Ion-Accumulator-pack, a loading-chipset hardware breakout and a miniUSB-plug.

Accumulator, USB-and-loader-breakout and Everdrive.

First a view from the workplace: In front you see a not-yet-functional 3D-printer (software issues). The GameBoy workplace is just beneath it, you cannot see it.
Workplace
Here you see all the parts, on the backside is a cutout because there were not enough space.
All the needed parts.

Ok, first he opened that the GBC and the Everdrive. For the GameBoy you need a special screwdriver with three 3 "corners". (NOT a triangle! It's like a normal screwdriver but...triple.)

He soldered a cable to each pin of the GameBoy-hardware and put in the Accumulator and loading-stuff.
First try with cables.

Soldering the cables together.

After that he soldered it to the Everdrive and tried to close the case.
All done, does it fit?

It's not possible, so he unsoldered the Everdrive and made a special PCB only to connect the two pieces together.
PCB for the second try.
That glassy thing is a selfmade PCB-creator. It's just some ultraviolett LEDs and a glass plate and some covering, I don't know how it works exactly.

He then cut the wires short and soldered the PCB on the GBC and the Everdrive on the PCB.
 
PCB, GBC and Everdrive soldered together.

PCB sideview.

Problem is, it will not fit to the case either. The case needs to be extended, with some parts changed.

SneezyCerritus used some 2-component superglue to create the outer shell of the expansion on the original case. Then another friend removed the inner parts, until only the superglue-case was left.
Some glue on the right place...

..makes the shell bigger.

Getting rid of the stuff inside.
When you fail in this (there was a hole where no hole should be), you can use some more glue to fix it, easy. The battery case cannot be opened anymore so the accumulator is necessary from now on.

He put it all together but it won't fit either. The PCB was to big.

The last solution for that issue (which finally worked) was to take a ribbon cable like on that image here:
 

Here you see an image from the de-soldering process, with the ribbon cable in the background.
De-soldering the PCB.

After that, soldering the stuff to the ribbon cable:
Nice view with ribbon cable.

Third and last soldering process. :)

Two LEDs were included into the case to indicate if the battery is charging or fully loaded:
Loading LEDs.

After reassembling, the working test...it works:


Do you like the color? I do.

It is now possible to use the internal microSD-card OR an original cardridge. You can even take out the microSD-card without opening the whole case. It's not very beautiful but it makes its job.

microSD-card slot.
Switch for cardridge-or-microSD-operation.
microUSB-slot for charging battery.
And finally, homebrew software running on the "original" device:
Homebrew Software. YAY!

That's it, all is working like it should. This project lasted over several months.

Sorry for the long post, I hope you enjoyed it.

Sonntag, 9. August 2015

GameBoy Color: Getting Started

I found a Gameboy Color somewhere, and while my friend is modding it to the max on hardware side, I am unable to find any programming sources explicitly for GBC.

All I can find is for GameBoy (original) or for GameBoy Advance.

I want to program the infrared sensor which is GBC only, so I need some reference for GBC.

First of all, when using GBC mode, you need to modify some stuff to "get the graphics back" (which you already have in your GameBoy-NonColor-Game).

It lasted some time to just get the printf()-output back to screen, and here is what you have to do.

Development Setup

[EDIT] You just need to set up palettes and use the GBCSetup-method below. The rest is just for consideration, you can also use gb/drawing.h to draw stuff and print text.

Linux:
Search for a good GameBoy emulator. I am using VisualBoy Advance, which is available over the Marketplace from Ubuntu.

Download the GameBoy Development Kit GBDK from sourceforge.net:
http://sourceforge.net/projects/gbdk/ 
gbdk ben0bi Edition ;)

1. Unpack the archive somewhere. Mine is in the users root directory.
2. Set the path to your installation. Type in your console:
export GBDKDIR=/home/ben0bi/gbdk

Now you should be able to compile the examples. Go into the examples directory and type make.

If all went good, you should have several .gb files now which you can start with the emulator.

In the directory examples/colorbars you will find a Makefile which sets the flag to GBC instead of GB in the last two lines.

Copy it to your project folder, alter the file names in it and set the right path to lcc on the top. You can use it yourself now.

Here is a Makefile which compiles two source files into a GBC-rom.
I needed some time to find out how the second file (core.c) has to be added to the compile-workflow as a "library".

It patches byte 0x143 in the header of the ROM to the value 0x80 (GB + GBC Mode) or 0xC0 (GBC only mode)
-> -Wa means "pass the next arg directly to the asm-compiler."
-> -Wl means "pass the next arg directly to the linker".
-> -ypX=Y means "patch byte X to value Y"

The Makefile

I don't get exactly how it works, but it..works..like that.

WARNING: The first two commands were suited otherwise. I got the parameters wrong by some functions, so I changed it.
They were made for a project with just one source file.
(Or I don't get it at all)

Instead of:
    $(CC) $(CFLAGS) -c -o $@ $<
I wrote:
    $(CC) $(CFLAGS) -c $<

-c means "compile only" and -o means "create output file" or something like that.
Some stuff only needs to be compiled and then linked together.

# Set the path to the compiler with some parameters.
CC    = ../bin/lcc -Wa-l -Wl-m

# Some other params... (why here?)
CFLAGS    = -DGBDK_2_COMPAT

# To get your other .c files compiled, add them here as .o-file
BINS    = mylib.o \
                someCfile.o \
                IRremote.gbc

# Refer to BINS for "make all" / "make"
all:    $(BINS)

# What files are created from which files...(I think. (?))
%.o:    %.c
    $(CC) $(CFLAGS) -c $<

%.o:    %.s
    $(CC) $(CFLAGS) -c $<

%.s:    %.c
    $(CC) $(CFLAGS) -S -o $@ $<

%.gbc:    %.o
    $(CC) $(CFLAGS) -o $@ $<

# The clean command: Just remove all the stuff which is not needed.
clean:
    rm -f *.o *.lst *.map *.gb *.gbc *~

# Link file, and write 0x80 at position 0x143 in header
# 0x80 is GBC compatible, 0xC0 is GBC-only.
# link together all the files which are created -> add your .o files.
IRremote.gbc:    IRremote.o
    $(CC) $(CFLAGS) -Wl-yp0x143=0xC0 -o IRremote.gbc IRremote.o mylib.o someCfile.o

Ok, we can now generate GBC-only-ROMs, but they show nothing with normal GB-code.

The Code

First, a hello world program which runs on normal GameBoys, no problem at all:

#include <stdio.h>
#include <gb/gb.h>

int main()
{
    printf("Hello World!");
    return 0;
}
You don't even need to give some compiler options, just type lcc -o myfile.gb myfile.c (You need to give the right path for lcc, though) and test it with vba myfile.gb.

Now, if you patch it, it won't work properly anymore.

Patching goes like this (without Makefile):
lcc -c -o myfile.o myfile.c
lcc -o -Wl-yp0x143=0x80 myfile.gb myfile.o
Remember: GBC ONLY needs the flag 0xC0 instead of 0x80.

Well then, let's do some stuff to get that "Hello World!" back on screen.

The following shows how to set up tiles (for background, I think foreground is almost the same.) and colour palettes to use with GBC. Finally some stuff will be drawn on the screen. Problem here is that printf and tiles don't work well together. (It works for printf if you only do the palette stuff.)
We need one or more palettes with some colours in it. We can have up to 8 palettes, but one is enough for now. Also, we need to check the hardware if it is really a GameBoy Color (only this one has IR-stuff.) These are the Values to check, they are defined in gb/gb.h ;)
DMG_TYPE 0x01 /* Original GB or Super GB */
MGB_TYPE 0xFF /* Pocket GB or Super GB 2 */
CGB_TYPE 0x11 /* Color GB */

Here is the source code for the absolute minimum. You can extend it at your belief, there are some comments about "the other stuff".

#include <gb/gb.h>
#include <stdio.h>

//+++++++++++++++ Stuff to check for Hardware-Version.
extern UBYTE _cpu;          /* Check this var for... */
// the other defines are in gb/gb.h //+++++++++++++++ EndOf Stuff for Hardware-Check

//+++++++++++++++ Palette Stuff
// Some palette indexes. Possible: 0 - 7
#define PAL_BACK_DEFAULT  0  // Background default palette on index 0
#define PAL_DEFAULT 0 // That would be the palette index for sprites. (Foreground)

//********* Palette Definitions -> Here are the colors.
// 4 Shades: First is Background Color (black), last one (blue) is Font Color
// Positions in the Tile-Editor (later): 0,2,1,3

const UWORD pal_def_default[] = { RGB_BLACK, RGB_WHITE, RGB_GREEN, RGB_BLUE };
// ... define some more ...

//********* EndOf Palette Definitions
//+++++++++++++++ EndOf Palette Stuff

//+++++++++++++++ Some Tile Data
// I will only show how 8x8 tiles work,  I don't know if 8x16 is just 2px
// instead of one or if it can be defined separately.
// One tile has 16bytes assigned, that are 2bit for each pixel = 4 colours.

// the hardware start adress -> must be a define to make an enum later.
#define adress_characters 0x00     
const UBYTE count_characters=2;  // how many characters are there
const UBYTE data_characters[] =   // the characters (tiles) itself.
{
      0x00, 0x00, 0x00 0x18, 0x00, 0x24, 0x00, 0x42, 0x00, 0x42, 0x00, 0x7E, 0x00, 0x42, 0x00, 0x42, // A - starts at adress Adress+0
      0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F  //  some junk ;) - starts at adress Adress+1
// ...don't forget the comma ^
}

// if you have many tiles in one array, you can refer to the tiles with an enum:
enum
{
     tile_A=adress_characters, // adress_characters CAN NOT be a variable. :(
     tile_B, tile_C,   // ... every name here is adress_characters + x ;)
} eTiles_characters;

// now every tile is at (tileadress)+position where position a counter for each whole tile of 16bytes. (a=0, b=1, c=2 etc.)

//+++++++++++++++ EndOf Tile Data

//+++++++++++++++ Function Bodies
void GBCSetup();       // this method sets up the graphics for GBC.
void load_palettes();  // load and assign palettes into hardware.
void load_tiles();        // load the tiles into the hardware.
//+++++++++++++++ EndOf Function Bodies

int main()
{
   GBCSetup();

   printf("Hello World!");
   return 0;
}


Now load the palettes and tiles into the hardware and then the almigthy GBCSetup function:
// load the palettes
void load_palettes()
{
// Params: Palette-Index, Unknown, Start-Position

    set_sprite_palette(PAL_DEFAULT, 1, &pal_def_default[0] );
    // ...define some more (foreground)...

    set_bkg_palette(PAL_BACK_DEFAULT, 1, &pal_def_default[0] );    // ...define some more (background)...
}

// load the tiles into the hardware.
void load_tiles()
{
    // load the background tiles.
    set_bkg_data(adress_characters,count_characters, data_characters); // start adress, tile count, tile-array   
}

// Set Up GameBoy Color
void GBCSetup()
{
    if(_cpu!=CGB_TYPE)
    {
        // It's not a GBC, nothing to do here.
        return;
    }

    // turn off display and disable interrupts.
    disable_interrupts();
    DISPLAY_OFF;

    // set tile size in LCDC-register. 0x67 = 8x16 tiles.
    LCDC_REG = 0x63; // 8x8 tiles

    // load palette data
    load_palettes();

    // Put the tiles into the tile-buffer.
    load_tiles();

    // reset display and re-enable interrupts.
    DISPLAY_ON;
    enable_interrupts();
}

Now we have a tile (exactly two but the last one is junk.)
We can put the tile on the screen with some functions...

A function to draw a background tile:
// the define is just a shorcut. #define render_back_tile(x,y,tile,palette) render_background_tile(x,y,tile,palette) void render_background_tile(UBYTE x,UBYTE y,UBYTE w, UBYTE h,UBYTE tileIndex,UBYTE paletteIndex)
{
    UBYTE c, d;
    UBYTE til[]={tileIndex}; // somehow it is needed as array. Idk why.
    UWORD pal[]={paletteIndex}; // somehow it is needed as array. Idk why.

    VBK_REG=0; // set background tileregister or something)
    set_bkg_tiles(x,y,w,h,til);  // put the tile into hardware (only with VBK_REG==0)

    // now set it to set the palettes.
    VBK_REG=1;

    // set the palette at that position, maybe for multiple tiles.
    if(w*h==1){
         set_bkg_tiles(x,y,w,h,pal);
    }else{
         // if we are rendering multiple tiles, we need to set the attributes for all tiles.
        for(c=0;c<w;c++)
            for(d=0;d<h;d++)
                 set_bkg_tiles(x+c,y+d,1,1,pal);
    }
}

For drawing something, you just have to wait until the vblank-interrupt is called with wait_vbl_done(); after or before drawing. (I don't see any difference on the emulator.)