Simple Sample Series
In this series we'll take a look at simple examples to do essential tasks! Lesson
S1 - Bitmap Drawing on the N64 Lets learn how to draw a bitmap onto the screen at a specified location on the N64 |
N64_Bitmap.asm |
Drawing a bitmap
We're going to draw our mascot onto the screen. | |
Ok, Lets start our program. First we tell our assembler (ArMips) we're compiling for the N64, we are going to save to "\RelN64\cart.N64", and our cartridge needs to start at memory address 0x80000000 |
|
We need to define a header for our cartridge. This has things like our program name, country and other useful factoids. It also contains a CRC (calculated Checksum) which needs to be correct, but we'll fix that with 'rn64crc' later. |
|
We need a 'bootstrap' to start up the n64. We have two options... 1.Code up 1000 lines of code - or 2. patch in a Binary file we 'borrowed' to do the job. We'll use option 2 - actually many commercial games use the exact same bootstrap! |
|
We want to pad our cartridge to 8Mb, so we add a 'footer' to do this | |
OK! We need to set up our screen! Our screen will be 320x240 - 16 bpp (32,768 colors) it will start from memory address 0xA0100000 The video registers start from address 0xA4400000 - the values shown here will set up the screen. |
|
Ok, Now for our little program! First we'll clear the screen... 'CLS' sets the screen to the color in A0. The color is 15 bit in the format %RRRRRGGGGGBBBBB- We use 'GetScreenPos' to calculate the VRAM destination for the position we want to draw the bitmap - it returns the VRAM address in A0 We show our character with 'DrawBitmap', this takes a width and height, and a source address for the bitmap Then we'll stop - ending with an infinite loop |
|
Here is the result |
Clearing the screen
Lets clear our screen Our VRAM starts at 0xA0100000 , and each pixel is one Half (two bytes)... the total screen size is 320*240 pixels Our colors are defined by 5 bits per channel in the format %RRRRRGGGGGBBBBB- We write our color to all the pixels. |
RAM
on the N64 is in BIG ENDIAN format! Meaning that the Half 0x1234
would be stored as 0x12 0x34 in memory. That doesn't affect CLS, but our bitmap needs to be in the correct format |
GetScreenPos
We want to calculate a screen position! We pass an Xpos in A0 and Ypos in A1 and calculate the final destination in A0 As the first few lines are offscreen, the formula we use to calculate the vram destination is: Vram = 0xA0100000+320*2*14 + (320 * 2 * Ypos) + (Xpos * 2) |
DrawBitmap
We need to create a valid bitmap file to show to the screen. The pixels are in the format %RRRRRGGGGGBBBBBB- On the N64 The data is in BigEndian format. |
|
We transfer each line of our source bitmap to the screen. We do the bitmap line by line, moving our VRAM destination down one 320 pixel line after each line |
|
Need to convert your bitmap? No problem! My Akusprite Editor can convert bitmap files to the correct format. Take a look at the MIPS menu -> N64 -> Save Raw Bitmap It will output a binary file in the correct big endian format for this example |
We could make
our drawbitmap more efficient if we worked in words (pair of
pixels) instead of halves (Pixels), but for clarity we're working
in single pixels here. |
Lesson
S2 - Sprite Movement and Joystick on the N64 Lets draw a sprite to the screen, and move it with the joypad |
N64_Joystick.asm |
Drawing a bitmap
We're going to draw our mascot onto the screen. We'll move it around the screen, but limit it so it can't go offscreen. |
|
Ok, Lets start our program. First we tell our assembler (ArMips) we're compiling for the N64, we are going to save to "\RelN64\cart.N64", and our cartridge needs to start at memory address 0x80000000 |
|
We need to define a header for our cartridge. This has things like our program name, country and other useful factoids. It also contains a CRC (calculated Checksum) which needs to be correct, but we'll fix that with 'rn64crc' later. |
|
We need a 'bootstrap' to start up the n64. We have two options... 1.Code up 1000 lines of code - or 2. patch in a Binary file we 'borrowed' to do the job. We'll use option 2 - actually many commercial games use the exact same bootstrap! |
|
We want to pad our cartridge to 8Mb, so we add a 'footer' to do this | |
OK! We need to set up our screen! Our screen will be 320x240 - 16 bpp (32,768 colors) it will start from memory address 0xA0100000 The video registers start from address 0xA4400000 - the values shown here will set up the screen. |
GetScreenPos
We want to calculate a screen position! We pass an Xpos in A0 and Ypos in A1 and calculate the final destination in A0 As the first few lines are offscreen, the formula we use to calculate the vram destination is: Vram = 0xA0100000+320*2*14-2 + (320 * 2 * Ypos) + (Xpos * 2) |
DrawBitmap
We need to create a valid bitmap file to show to the screen. The pixels are in the format %RRRRRGGGGGBBBBBB- On the N64 The data is in BigEndian format. |
|
We transfer each line of our source bitmap to the screen. We XOR with the screen data - this means if we draw twice the sprite will be removed We do the bitmap line by line, moving our VRAM destination down one 320 pixel line after each line |
Reading the joystick
The N64 controllers are connected via the so called 'PIF' chip
(Peripheral Interface?) The base of the PIF registers is at address 0xBFC007C0 To initialize things we first write 0x8 to the status register at 0xBFC007FC |
|
We're going to use the serial interface (SI) to send data to
the PIF, This is basically a DMA copy, which sends a block of data. We need to prepare a 96 byte block of data to send to the PIF to initialize things. We also define 8 bytes to get back the results when we do a read! |
|
OK we need to use the SI to Send the INIT code to the PIF The SI registers are at 0xA4800000+ We need to calculate our source address (PIF_Init) - but we need the true 'hardware address' we can get this by ANDing with 0x1FFFFFFF We send the source address to 0xA4800000 (SI_DRAM_ADDR_REG) We want to transfer to the PIF ram at 0xBFC007C0 (PIF_RAM_START) - we also AND this with 0x1FFFFFFF We write the destination to the write register at 0xA4800010 (SI_PIF_ADDR_WR64B_REG) - this write also starts the transfer |
|
We define the start XY position for our player. We draw the player to the screen. |
|
the N64 is FAST! At the start of the main loop We have a crude delay to slow it down and make our example usable! |
|
OK, it's time to read in from the joystick! This time we use the
SI to READ from the PIF. We need to calculate our destination address (PIF_JoyState) - but we need the true 'hardware address' we can get this by ANDing with 0x1FFFFFFF We send the destination address to 0xA4800000 (SI_DRAM_ADDR_REG) - this is the same as the address for writing This time we want to transfer FROM to the PIF ram at 0xBFC007C0 (PIF_RAM_START) - we also AND this with 0x1FFFFFFF We write the source to the read register 0xA4800004 (SI_PIF_ADDR_RD64B_REG) - this write also starts the transfer |
|
We wait for a direction to be pressed... When one is, we draw the sprite in the same position again, because it's XORed, this removes the sprite. |
|
We now test each direction, Right, Left, Down and Up If a direction is pressed, we check the position of the sprite. If the sprite is at the limit of the axis, we cannot move, otherwise we adjust the position accordingly. |
|
We draw in the new location... and repeat! |
This
is a very crude example, and doesn't use any 3D hardware or
anything! It's just a simple example to get something moving onscreen, so you can play with it as you learn mips! |
Lesson
S3 - Bitmap Drawing on the PSX Lets learn how to draw a bitmap onto the screen at a specified location on the Playstation |
PSX_Bitmap.asm |
Drawing a bitmap
We're going to draw our 'Chibiko' mascot to the screen Our bitmap is 16bpp in Little Endian in the format %-BBBBBGGGGGRRRRR |
|
Ok, Lets start our program. First we tell our assembler (ArMips) we're compiling for the PSX, we are going to save to "\BldPSX\Prog.bin", and our cartridge needs to start at memory address 0x80010000 |
|
We need to set up our screen. We use the IO registers from address 0x1F800000+ We set up a 320x240 16bpp screen |
|
Our 'Footer' just contains a close command | |
Ok, Now for our little program! First we clear the screen - We load the color command into A0 before calling CLS Now we draw our sprite We load A0 with our Xpos,A1 with our Ypos, and the pointer to our bitmap into A2. We call DrawBitmap Then we'll stop - ending with an infinite loop |
Clearing the screen
we need to command the GPU with port 0x1F801810 We use GFX command 0x2 to fill the screen. Our fill color is defined by 8 bits per channel in the format 0xBBGGRR The total screen size is 320*240 pixels, we define the fill area with the following 2 commands The GPU will then clear the screen for us. |
We
can't actually write directly to the PSX screen - We have to use GFX commands. To draw our bitmap, we define a 'window', then stream the pixel bytes into that window |
DrawBitmap
We need to create a valid bitmap file to show to the screen. The pixels are in the format %RRRRRGGGGGBBBBBB- On the N64 The data is in BigEndian format. |
|
To send our bitmap data we first need to set up the GPU with the
parameters of the area we'll draw to. We use command A0 to select the 'Send image' command Next send the X,Y pos. Then we send the Width and Height We also calculate the word count for sending the bitmap data |
|
We send all the words of our bitmap to the VRAM via the GP0 port | |
Need to convert your bitmap? No problem! My Akusprite Editor can convert bitmap files to the correct format. Take a look at the MIPS menu -> PSX-> Save Raw Bitmap It will output a binary file in the correct format for this example |
Lesson
S4 - Sprite Movement and Joystick on the Playstation Lets draw a sprite to the screen, and move it with the joypad |
PSX_Joystick.asm |
Drawing a bitmap
We're going to draw our mascot onto the screen. We'll move it around the screen, but limit it so it can't go offscreen. |
|
Ok, Lets start our program. First we tell our assembler (ArMips) we're compiling for the PSX, we are going to save to "\BldPSX\Prog.bin", and our cartridge needs to start at memory address 0x80010000 |
|
We need to set up our screen. We use the IO registers from address 0x1F800000+ We set up a 320x240 16bpp screen |
|
Our 'Footer' just contains a close command | |
OK! We need to set up our screen! Our screen will be 320x240 - 16 bpp (32,768 colors) it will start from memory address 0xA0100000 The video registers start from address 0xA4400000 - the values shown here will set up the screen. |
Drawing the Bitmap
We need to create a valid bitmap file to show to the screen. The pixels are in the format %-BBBBBGGGGGRRRRR On the PSX The data is in Little endian format. |
|
When we want to draw our bitmap to the screen we load the X and Y pos from Ram | |
We need to get the GPU to draw the bitmap data to the screen. We define the 'window' that our bitmap will occupy on the screen. |
|
We send the bitmap data to the GPU one word (two pixels) at a time |
Removing the Bitmap
We use the Fill Area command to remove our character from the
screen. Strangely it seems the start Xpos is limited to a 16 pixel alignment, so we clear an area 16 pixels wider than our sprite. We shade the removed area dark purple so we can see what was removed. |
The Fill seems to be
limited to clearing aligned to a 16 pixel boundary. This is probably related to the internal organization of the VRAM in the GPU |
Reading the joystick
We're going to execute the bios functions at address 0xB0 (the so
called 'B functions') We need to call this with a function number in T1 - Here we use 0x12 which is 'Init Pad' This takes 4 parameters in A0-A3 A0 is the address of the buffer for joypad 1, A1 is the size (Should be 0x22) A2 is the address of the buffer for joypad 2, A3 is the size (Should be 0x22) |
|
Once we have Initialized the joypad we can start the read process. We use Bios function 0x13 'Startpad' - which takes no parameters. This will automatically fill the buffer with the joypad data. |
|
We define the start XY position for our player. We draw the player to the screen. |
|
the PSX is FAST! At the start of the main loop We have a crude delay to slow it down and make our example usable! |
|
We wait for a direction to be pressed... When one is, we draw the sprite in the same position again, because it's XORed, this removes the sprite. |
|
We now test each direction, Right, Left, Down and Up If a direction is pressed, we check the position of the sprite. If the sprite is at the limit of the axis, we cannot move, otherwise we adjust the position accordingly. |
|
We draw in the new location... and repeat! |
This
is a very crude example, and doesn't use any 3D hardware or
anything! It's just a simple example to get something moving onscreen, so you can play with it as you learn mips! |