PSX Development

Official page address : http://www.horningabout.com/jimb/psx

Jimb Esser


Text - Sprites - GPU Status - MSVC++ - Postmortem

Displaying Text

The begining

I started my experiments by trying to display text. All of the examples I found were for Yaroze or something similar that we don't have access to in the lab (but I found the libs on some of the sites if you want them for your use). I found one example that was written in assembly. The only problem with this one was that it had an external file (which was included in the program at compile time) that it used for the font graphic data, and I could not get file access working so as to read in the file at runtime in a C program, since I know of no way to link a binary file with a C program at compile time. So, I wrote a short program that converted the FONT.BIN that came with the assembly program into a .h file that I could include in a C program. The resulting file is fontdata.h.

Porting the assembly

The first thing I tried to do was port the assembly code over to C. I did this as an ugly hack using lots of global variables and a 1<->1 conversion from .asm code to C code. That code is availible here : printGPU_asm.c. I ended up making a few changes from how the original program did the drawing... the original program used a 4-bit clut (Color Lookup Table), where each of the pixels in the texture buffer took up 4 bits (instead of 16bits), and it looked up the associated color from a table. Unfortunately, I was not able to get this to work. I believe it was because of a problem loading the clut into memory. I decided to just change the character graphics to larger 15bit values and ignore using the clut.

Cleaning up the assembly

Then, I cleaned up the program, drastically decreasing the size and (hopefully) efficiency, yielding this. Lastly, I converted the code to a form that uses a struct similar to the examples provided, which may, or may not, make more sense, depending on how your brain works. This code is what is probably the most useable, since it also provides a framework for an easy way to implement sprites. That code is here : printGPU_sprite.c. You can also download a precompiled .exe : printGPU_sprite.exe.
I also took the important code out and it is availible as just a .c and .h file you can link with your programs : printGPU.c, printGPU.h.

How printing text works

In order to use this code in your own programs, you need to do 4 things:
  • include "fontdata.h";
  • include the printGPU, p2gpucommand, and WaitGPU functions and the SPR_X define in your program
  • call loadfont() after initializing the GPU
  • call printGPU("text", x, y, color) to display text
The loadfont() function call makes a call to mem2vram to copy the data from fontdata.h into the Texture Buffer. A Texture Buffer can be any part of the display buffer (preferably offscreen) aligned at x = a multiple of 64 and y = 0 or y = 256. The font data is currently set up to take up a 256x64 chunk at (SPR_X, 0). SPR_X is defined as 512, but you can change this within reason (can't extend past the end of the display buffer itself, whose size depends on the calls in gpuInit()).

The printGPU function steps through each of the characters in the string, finds the appropriate texture coordinates for the character, and draws 2 8x8 sprites to the output coordinates in order to copy the 8x16 character graphic.


Text - Sprites - GPU Status - MSVC++ - Postmortem

Displaying Arbitrary Sprites

By looking in the GPU reference, I was able to find the codes and syntax of the commands to draw sprites. I set up a struct like this :
	typedef struct {
		PsxUInt8 r,g,b,code;
		PsxUInt16 x,y;
		PsxUInt8 u,v; PsxUInt16 clut;
	} SPRITE;
That takes the parameters need to draw a sprite. r, g, and b are obviously the colors to draw with. code is one of :
  • 0x74 - 8x8 sprite
  • 0x7c - 16x16 sprite
x and y are the destination coordinates to draw to. u and v are the Texture coordinates within the current Texture Page (defined with GPU command 0xe1). And clut is the address of the color lookup table, where the high 10 bits (0xFFC0) are the Y and the low 6 (0x003F) are the x coordinate / 16.

Defining the texture page

To define the texture page you're drawing sprites from, you use the GPU command 0xe1. The bit-layout of the command is (take from gpu.txt
      |1f-18|17-0b|0a |09 |08 07|06 05|04|03 02 01 00|
      |0xe1 |     |dfe|dtd|tp   |abr  |ty|tx         |
    
    tx       0-f      X*64  texture page x coord
    ty       0        0     texture page y coord
             1        256
    abr      0        0.5xB+0.5 xF  Semi transparency mode
             1        1.0xB+1.0 xF
             2        1.0xB-1.0 xF
             3        1.0xB+0.25xF
    tp       0        4bit CLUT
             1        8bit CLUT
             2        15bit direct
    dtd      0  Ditter off
             1  Ditter on
    dfe      0  Draw to display area prohibited
             1  Draw to display area allowed
    
I pretty much ignore arb, dtd, and dfe, leaving them as what they were in the gpuInit() function. So, if we had our texture sitting in memory at (512,0) and we're using 15-bit direct for our sprites, as I did in my font drawing, we would call:
   GPU_cw(0xe1000708);
This value can be assembled using bit-wise functions like this:
void setDrawMode(PsxUInt16 tx, PsxUInt16 ty, PsxUInt8 abr, PsxUInt8 tp, PsxUInt8 dtd, PsxUInt8 dfe) {
	PsxUInt32 command;
	if (ty!=0) {
		ty = 1;
	}
	tx = tx >> 6; // Divide by 64
	command = (0xe1 << 0x18) |
		(dfe << 0x0a) |
		(dtd << 9) |
		(tp << 7) |
		(abr << 5) |
		(ty << 4) |
		tx;
	GPU_cw(command);
}

Text - Sprites - GPU Status - MSVC++ - Postmortem

Displaying GPU status

While programming and debugging, I was running into some really weird problems (it seems to be a bug in mem2vram, but I haven't verified it yet), so I wrote a function that verbosely displays the status of the GPU. It takes the result of GetGPUStatus() and displays the text equivalent of the 20 fields returned. This code is included in all of the above files, in a function called DisplayStatus().

Text - Sprites - GPU Status - MSVC++ - Postmortem

Developing in the MSVC++ IDE

Being that I have yet to find a better C/C++ environment than MS's Visual C++, I immediately configured it to allow me to compile and run PSX apps from within the IDE. If you're interested in doing this, it really only takes 4 steps:
  1. Download and unzip the Dos/Win32 GNU PSX development environment, and do the same for FPSE. Both of these and and example project are included in this .zip file : msvcpsx.zip. The example project file assumes it is operating out of E:\PSX, FPSE is in E:\PSX\FPSE, and it runs printGPU_sprite by default.
  2. Create a new Utility Project. These allow you to define your own build scripts, like using GNU's compilers instead of MS's. Consequentially, you can use this same method to compile *any* type of code, like Java or Perl for example.
  3. Add a new or existing C/C++ file, and right click on the file in the file explorer, choose Settings. Under the Custom Build tab, you define the commands and output. Enter the string "$(InputName).exe" as the output (without quotes), and I use this script for my commands (cut and paste it, after modifying the directory/drives).
  4. Under Project Settings, Debug tab set the Executable for Debug Session to the full path to FPSE.EXE, the Working Directory to the directory FPSE is in, and the Program Arguments to a full or relative path to the executable you want to run (the one generated in the above script - same name as your .c file, but as a .exe).
One person reported errors with "Insufficient Memory Space" when running the above mentioned script. There are a few solutions, here's what I had sent back to him in email:
    What you need to do is up the memory that CMD.EXE or COMMAND.COM uses for evironment, or set these variables globally.

    If you are using Windows NT, 2K, 2K3, or XP, you can set these environment variables under Control Panel | System | Advanced | Environment Variables, or something like that.

    Otherwise, you want to up the memory for command.com. In Win9x, you can put something like this in your autoexec.bat file:
    SET COMSPEC=C:\COMMAND.COM /E:8192
    Or (probably the easiest way out of all of these), make one batch file that has all of these commands you want to run like this.

    And then in MSVC++ have the script run this:
    C:\COMMAND.COM /E:8192 /C WORKER.BAT $(InputName)
    You may need to replace "C:\command.com" with "C:\cmd.exe" or "c:\windows\system32\cmd.exe"

Text - Sprites - GPU Status - MSVC++ - Postmortem

What I learned

  • Everything I ever wanted to know about CLUTs, except, perhaps, why mine wasn't working.
  • BabelFish knows Japanese better than I do, but knowing a little Japanese helped dig through some pages.
  • Although very low-level gpu.txt has lots of good information, and makes sense after reading it a few times, and consuming enough Mt. Dew. Similarily, I'd assume gte.txt, spu.txt, system.txt, and cdinfo.txt (all by the same group, I believe) are just as good.

Back to Jimb Esser's Homepage
Back to CSci 5980 Lab Sction