Overview of VRAM in Different Modes.

 

Your first gba program

Here is the first program, copy it into notepad and store it as Test.cpp. Try to compile it by double clicking the Make.bat file, and run the Test.gba on the emulator. You will probably have to go back to the end of lesson 2 to get the details on how this should be done. Remember that you need to put all those header files into your folder (copy them in, and store them with the same name as in lesson 2).

 

#include "gba.h"

 

int main()

{

u16 x;

SetMode(MODE_3 | BG2_ENABLE);

           

for(x=0; x<(240*160); x++)

            {

                        FrontBuffer[x]=RGB(31, 0, 0);

            }

            return 0;

}

 

If you were able to compile and run this example, you should get a red screen on your gba emulator as shown below.

 

 

The first line in this program imports all those header files I told you about in lesson 2, and it looks like this.

 

#include "gba.h

 

The first line in the main() function looks like this.

 

SetMode(MODE_3 | BG2_ENABLE);

 

SetMode is a macro from the header file gba_video.h, and is used to set which video mode we are going to use in our code. In this example we choose to use mode 3 and that has a graphical resolution of 240x160 in 32768 colors. We also choose background 2, because this is the only background available in mode 3 (look in lesson 1 for overview on this). The way we set modes and backgrounds might be hard to understand if you have not seen this kind of thing before, but I will try to give an explanation here.

 

The macro SetMode is defined as follows.

 

#define SetMode(mode) REG_DISPCNT = (mode)

 

This means that it takes the value that we input after SetMode and assigns that value to the register defined as REG_DISPCNT.

 

REG_DISPCNT is a 16 bit register at address 0x4000000, it is maybe the most important register in the GBA.

 

On a bit level, REG_DISPCNT looks like this.

 

 

15

14

13

12

11

10

9

8

7

6

5

4

3

2

1

0

XX

XX

XX

OBJ

BG3

BG2

BG1

BG0

FB

OM

HB

DB

XX

MODE

 

 

 

 

Bits 0-2 Decides which graphics mode the screen is going to have, a value between 0 and 5. Bit 3 Not used

Bit 4 Decides which buffer we are going to use when using double buffering in mode 4 and 5.

Bit 5 Gives us the possibility to update OAM (sprite attribute data) during horizontal blank

Bit 6 Set the mapping mode for sprites 1D=0 and 2D=1.

Bit 7 Screen goes white (Forced Blank)

Bit 8-12 Set which background(s) we want to use, and set sprites on or off.

Bit 13-15 Not used.

 

If we look at MODE_0 and BG2_ENABLE in gba_video.h you might see that the value we have set for MODE_3 is 0x3, or as binary;

 

0000 0000 0000 0011

 

The value of BG2_ENABLE is 0x400 which is binary;

 

0000 0100 0000 0000

 

When we write SetMode (MODE_3 | BG2_ENABLE);

 

The following will happen;

 

0000 0000 0000 0011                        (MODE_3)

 OR     0000 0100 0000 0000                        (BG2_ENABLE)

  =>     0000 0100 0000 0011           

 

The operator | executes a logical OR between the two values (0x3 and 0x400). The result is then put into REG_DISPCNT, and then we are ready to write graphics to the screen.

 

The next line of the program.

 

u16 x;

 

This is only to define an unsigned short variable that is called x. u16 is defined as unsigned short, unsigned means that the variable can not contain negative numbers.

 

The gba screen (which is 240x160 pixels) is drawn the same way as a regular television screen, which means that it starts drawing in the upper left corner (pixel 0,0) and moves toward the right side of the screen. When the pixel is at pixel (239,0) it goes back to the left side of the screen (this is called HBLANK) and starts all over again at pixel (0,1). From here it moves right to pixel (239,1). In this way the whole gba screen is drawn line by line until it gets to point (239,159) then its a little break (called VBLANK) before it moves back to pixel (0,0) and starts drawing all over again. The screen is drawn about 60 times each second.

 

The next new thing in this program is FrontBuffer, which is a pointer to the video memory (VRAM). A pointer can be used with an index to reference data in the same way as an array, and that is what we are doing in this line.

 

FrontBuffer[x]=RGB(31, 0, 0);

 

The pointer points to different pixels on the screen, and the value that comes from RGB(31, 0, 0) is used to set the color of this specific pixel, FrontBuffer[x] (remember its 32768 colors available in mode 3).

 

I am setting the color of every index with the RGB macro that was described in lesson 2. As you might see from the program I have set the red value to 31, that is the maximum, and the two other values green and blue are 0. This is why all the pixels on the screen are red when you run the program.

 

The For-loop is actually indexing all the indexes in FrontBuffer and setting them all to the RGB value for red.

 

for(x=0;x<(240*160);x++)

 

The last program line.

 

return 0;

 

This is because in c we use int main() in the start of the program. Lots of people use void main() in c++ programs, but here we have to use int main(), anything else wont work.

 

I will try to explain a little more exactly how the screen memory (VRAM) in mode 3 works. Each little square in the picture underneath is an address in the screen memory and is made up from an 8 bit value. The gba can only write 16 bit values to memory at a time. Because of this we had to define FrontBuffer as a u16, so that each time we write a 16 bit value to an index it will be split up into two parts, each of 8 bits, that will be written to two adjacent addresses.

Something you should keep in mind is that the gba only have 15 bit colors (2^15=32768), the most significant bit is ignored.

 

Here is an example: VRAM starts at 0x6000000, which means the pixel in the upper left corner (pixel 0,0) has address 0x6000000. If we now write a 16 bit value to FrontBuffer[0], that is the same as address 0x6000000, this value will be stored in the two addresses 0x6000000 and 0x6000001. In this way we see that each of the addresses get an 8 bit value. If we then write to the next pointer index that is FrontBuffer[1] and start at address 0x6000002 (because its a 16 bit pointer, and each address only has space for 8 bit). This value, will then be split in two and stored at address 0x6000002 and 0x6000003. It goes on like this until we have addressed the whole screen.

 

This might seem a little hard to address single points on the screen.  I mean what if you want to place a pixel at (12,20)?  Well if you use this little ‘trick’ you will be able to exactly tell the gba where you want your graphics.

 

#include "gba.h"

 

int main()

{

u8 x,y; 

SetMode(MODE_3 | BG2_ENABLE);

           

for(y=40;y<120;y++)

            {

                        for(x=60;x<180;x++)

                        {

                                   FrontBuffer[(y*240)+x]=RGB(31, 0, 0);

                        }

            }

            return 0;

}

 

This program is pretty much the same as the first, but we have included two loops and we have exchanged FrontBuffer[x] with FrontBuffer[(y*240)+x]. The extra loop is because we want to use two coordinates (x and y) to reference the pixel. We have used the loops to loop through the pixels we want to draw so that we get a rectangle on the screen. The reason we have exchanged FrontBuffer[x] with FrontBuffer[(y*240)+x] is that we know that gba has 240 (0-239) pixels horizontally on the screen, if we set FrontBuffer[240] we will get a pixel at (0, 1). From this we see that by multiplying the y value by 240 we will get on the desired y coordinate (0, y). If we then add the x value we want to place our pixel, we will end up with the right address in FrontBuffer. Because of this the formula for a chosen point within x = 0-239 and y = 0-159 will be (y*240)+x.

 

 

 

We have now looked at mode 3 and how you can use this mode to show graphics on the screen. We have set 15 bit colors into the address area from 0x6000000-0x6013FFF. As we can see this takes up a lot of space (75Kb), and uses almost all of the VRAM (96Kb). We have a total of 240x160 = 38400 individual pixels that can have whatever color we want from a palette of about 32768 colors. This is the main reason mode 3 uses this much memory (the computer has to store a 16 bit value for each pixel on the screen).

 

We are now going to have a look at mode 4 which at first seems pretty much like mode 3 but with a big difference. Mode 4 uses something called a palette, this palette contains a maximum of 256 colors chosen (from the 32768 available) by the programmer. Gba uses two palette sizes, the smallest is 16 colors, and the biggest is 256. The 16 bit colors we stored in VRAM in the last example is now stored in palette ram. This is a special memory area from 0x5000000-0x50001FF of 512 bytes that contains either one palette with 256 colors or 16 palettes with 16 colors each. We can set the colors we wish to use in our graphics using these palettes. This works the way that the color we input at position 0x5000000 in the palette gets nr 0 in the palette, the color at address 0x5000002, gets nr nr l, and so on.

 

When we choose how the picture is going to be when we input the values (the palette number of the color we wish to use) into VRAM, these automatically use the colors from the palette if mode 4 is set, it is done by the hardware. The main advantage of using a palette is that we save VRAM, and that we are able to write two pixels at a time (you haven’t forgotten that you always have to write 16 bit to VRAM), but this time we write two palette entry numbers (that is two colors) instead of only one 16 bit color. The disadvantage of doing this is that we can only use 256 different colors on the screen at once.

 

We use the same part of memory in mode 4 as in mode 3, but we only use half of it, because we only write one byte for each pixel on the screen. In mode 4 we only need to use VRAM from 0x6000000-0x6009FFF (37,5Kb), this is exactly half of what we used in mode 3. The memory area from 0x600A000-0x6013FFF (37,5Kb) is now free, and can actually be used as a buffer if we want to use double buffering/page flipping. This part of the memory works exactly like the first. We have the opportunity to decide which part of  VRAM should be shown on the screen, by manipulating bit 4 in REG_DISPCNT.

 

This is a mode 4 picture and the palette for this picture.

 

 

 

We will now have a look at a programming example that shows a picture on the gba screen.

You can choose whatever picture you want, but it has to be exactly 240x160 pixels. The picture has to be converted to a format the gba understands. From what I just have told you, we need palette and a image data to show our picture. There are alot of programs to convert from PC to gba. We are going to use a program called PCX2GBA, this converter program demands that the file you are going to convert has these properties.

 

·        Maximum 256 colors.

·        Image size exactly 240x160

·        PCX image format

 

To be able to convert the picture you just drag the picture icon with your mouse pointer over the PCX2GBA icon and drop it.  You will then see a small dos window telling you the size of the image. If you press a key this window will dissappear. A new file will then appear in your directory with the same name as your image file but with the extension .h.  This file will contain all the information needed to show the picture on the gba.

 

Its very important that the name of the image file does not start with a number, because the name of the image file will also be the name of a table in the .h file you created, and as you know we cant use variables starting with a number. The converted image will look something like this.

 

 

/**********************************************\

*       bilde.h                                   *

*          by dovotos pcx->gba program         *

/**********************************************/

 

#define  bilde_WIDTH   240

#define  bilde_HEIGHT  160

 

const u16 bildeData[] = {         0x4909, 0x1B1B, 0x2767, 0x1B1B, 0x1B1B, 0x1B49, 0x1F27, 0x1B49, 0x1B1F, 0x4932, 0x091B, 0x601F, 0x1B1B, 0x1B16, 0x1B1B, 0x1B27, 0x161B, 0x161B, 0x1F1B, 0x351B,               0x161F, 0x091B, 0x6235, 0x1B13, 0x6016, 0x4616, 0x1B1B, 0x6216, 0x1F35, 0x6760, 0x6D63, 0x6264, 0x671B, 0x1F62, 0x6269, 0x6962, 0x6869, 0x6C63, 0x6469, 0x6369, 0x6464, 0x6969, 0x696D, 0x696D, 0x6969, 0x6969, 0x8E77, 0x5C77, 0x705F, 0x8071,...};

            

 

const u16 bildePalette[] = {     0x0000, 0x0021, 0x0060, 0x00A0, 0x0003, 0x0005, 0x0044,                                  0x00A3, 0x04C0, 0x00C0, 0x0100, 0x0100, 0x00C2, 0x0121,

0x00E2, 0x00E3, 0x0441, 0x0445, 0x1041, 0x1045, 0x0CC1, 0x08E4, 0x1CC1, 0x18C4, 0x28C0, 0x2901, 0x2D00, 0x3100, 0x28C2, 0x24E4, 0x2CE2, 0x30E4, 0x0028, 0x0828, 0x0867, 0x08C7, 0x044A, 0x044C, 0x08C9, 0x08CC, ...};

 

             

Here you see what I mean when I said that the file name is the same as the start of the array name. Both arrays bildePalett[] and bildeData[] are actually much longer than shown here, but its really not important to see all the numbers.

 

This program uses the image data to show the image on the gba.

 

#include "gba.h"

#include "bilde.h"

 

int main()

{

            u16 loop, x;

            SetMode( MODE_4 | BG2_ENABLE );       

 

            for(loop=0;loop<256;loop++)

            {

                        BG_PaletteMem[loop]=bildePalette[loop];     

}

 

            for (x=0; x<(120*160); x++)

            {

                        FrontBuffer[y] = bildeData[y] ;

            }

            return 0;

}

 

The first new thing in this program is that we include the header file bilde.h, which contains the two arrays bildeData and bildePalette. This is the information we need to get the image on the screen.

 

#include "bilde.h"

 

We set graphics mode 4, and background 2 on, which is the only background available in mode 3, 4 and 5.

 

SetMode( MODE_4 | BG2_ENABLE );       

 

The next lines load the content from the table bildePalette in memory, at address 0x5000000-0x50001FF. BG_PaletteMem is a 16 bit pointer to address 0x5000000. We use this as an array, the same way we did when we used FrontBuffer, and load the colors into palette memory. We can see that the loop goes all the way up to 256, because that is the amount of colors needed to show this image. If the palette only consisted of only 100 colors, our loop could stop at 100.

 

for(loop=0;loop<256;loop++)

{

            BG_PaletteMem[loop]=bildePalette[loop];     

}

 

The next loop loads the content of the bildeData table into VRAM so that the gba will know where on the screen to put the different colors. We are only using the memory area from 0x6000000-0x6009FFF (37,5Kb). This loop looks very much like the one used in the first program example with mode 3, but in this example we use 120 instead of 240. The reason for this is that when we write only half as many bytes (remember each color is a 1 byte entry into the palette) to VRAM as we do in mode 3. Because we always write 16 bit at a time, and the image converter has taken this into consideration, and put the two adjacent bytes together to form a 16 bit number that we can directly load into VRAM to get the picture on the screen..

 

for (x=0; x<(120*160); x++)

{

            FrontBuffer[y] = bildeData[y] ;

}

 

We can also address the screen with x and y, coordinates (as we did in the second example with mode 3), the result is the same but because we use nested loops this way is probably slower then the first one.

 

#include "gba.h"

#include "bilde.h"

 

int main()

{

            u8 x,y;

u16 loop;

            SetMode( MODE_4 | BG2_ENABLE );

 

            for(loop=0;loop<256;loop++)

            {

                        BG_PaletteMem[loop]=bildePalette[loop];

            }

            for (y=0; y<160;y++)

            {

                        for (x=0; x<120;x++)

                        {

                                   FrontBuffer[(y*120)+x] = bildeData[(y*120)+x] ;

                        }

            }

}

 

The result should be something like this.

 

This image is stored the way that the value that is at address 0x6000000 is one byte that refers to a color in the palette. If the value 2 had been stored at address 0x6000000, the gba would have figured out which the color that was nr 2 in the palette and put this in the pixel at point (0, 0). Address 0x6000001 contains a reference to the color in point (1, 0), address 0x6000002 contains a reference to the color in point (2,0) and so on.

 

Here we can see how color nr 127 in the palette is stored in VRAM, and where it is used in the picture (actually several places).