Troubleshooting
Most of what goes wrong in a PlayStation program goes wrong in one of a few ways, and the same few went wrong for Net Yaroze members in 1998, which is why many of the answers here are Sony's Programming FAQ's, said again for this toolchain. The emulator helps with all of them: psxemu prints what a program writes, saves what the screen shows and dumps video memory, and a test can read any of the program's variables by name.
Nothing on the screen#
- The program stopped before its frame loop. Run it in
psxemu, which prints what it writes: a Go panic says what it was there, and a file that could not be read is whateverdisc.LoadAllreturned. - A file is not on the disc.
discgendeclares the files that were underassets/when it last ran. Rungo generateagain after adding one, anddumpsxisolists what the disc holds. - The frame loop never draws. Everything has to be sorted into the table
Framesgives, inside the loop.
A sprite is missing#
Sony's answer to why a sprite cannot be seen is the checklist, and with this toolchain:
- Its image is not in video memory, or something drew over it.
TIM.Loadhas to run before the sprite is drawn. Two TIMs at overlapping places overwrite each other, as does an image under the font or inside the display buffers.tim2pngandpng2timprint where each one goes, andpsxemu --vramdumps video memory to look at. - Its palette was wiped. A 256-line screen on a PAL console reaches row 511, and its clear each frame wipes palettes kept at row 480.
Screenuses 240 lines unless asked for more for this reason. - It is somewhere else. With
GsInit3Dthe origin is the middle of the screen for 2D as well, so a sprite at 0, 0 is in the middle and one at 320, 240 is off the screen. Place things fromScreen.Bounds. - It is black or invisible. R, G and B of 0 draw nothing. 128 is the image as it is.
- It is drawn, behind something. At the same depth the last thing sorted is drawn first. A 3D model near the camera sorts at depth 0 too, and the overlay table,
Screen.OverlayDepth, is for what must be in front of a 3D scene. - Its holes are wrong. A texel of 0x0000 is not drawn.
png2timmakes transparent pixels that, and opaque black 0x8000, unless--black transparentmakes black transparent too.
Stray vertical lines in a sprite drawn with SortFast mean an odd U or width (the FAQ).
A model is missing or looks wrong#
Sony's checklist for models:
- The TMD was not mapped, with
TMD.Map, once, beforeLink. - Its texture is not in video memory, or not where the TMD says. Load the same TIM the model was converted with.
- It is unlit or lit black. Set a light with
GsF_LIGHT.Setand some ambient light, or convert it withobj2tmd --unlit. - It is too big, too small or behind the camera. A TMD's coordinates are 16-bit. A model a few hundred units across, a camera a few hundred to a thousand back and
GsSetProjection(320)is a good start, andrsdlink -vprints a model's extent. - It is inside out. Polygons are drawn from the side their corners go clockwise on the screen, and
obj2tmdturns an OBJ's faces round. A model made another way may need its faces reversed in the modelling program. - Faces are missing. The library does not draw double-sided polygons, lines, sprites or untextured gouraud quads from a TMD.
obj2tmd --bothmakes two faces back to back. - Faces flicker or show through each other. A deeper table,
Screen.Depth, sorts the polygons more finely.
The picture is garbled#
- The packet area is full. A frame that sorts more than
Screen.Packetsholds writes past it, and the GPU draws garbage, or the library prints a GPU code it does not know (the FAQ). RaisePackets. - A model was overwritten in memory. A TMD is read and mapped in place, and an array overrun into it scrambles the model.
- A packet area of the program's own is not aligned. The library stores words into it, so it must be an array of
uint32passed throughyaroze.Packets, not of bytes. The emulator reports the misaligned store.
The program freezes#
A Go panic on the console prints its message and stops, and the picture freezes. The message is in what psxemu prints, and in TTY() from a test. The usual one is an index out of range, often from code written after C, which let a program read one past the end of an array. The emulator reports an illegal instruction or a misaligned access where it happens, with the registers and the instructions before it.
"out of memory" is the heap: the files a program loads and anything allocated, which is never freed. Allocating in the frame loop runs out in time. Passing the address of a local variable to a library function allocates it on every call, so a program keeps such things in package-level variables.
It is slow#
psxemu --profile shows where a frame's time goes. Ranging over a large array by value copies it on every iteration, so range over a pointer to it. Floating point is emulated, so the arithmetic is fixed point. --polygons counts what the GPU drew each frame. Screen.Interval of 2 halves the frame rate evenly when a frame cannot fit.
No sound#
SsSetMVolwas never called. Nothing sounds without it.- The bank did not open.
OpenBankreports it. A bank too big for the SPU's 512 KB with another one open, or a VH and VB swapped, will not open. - The music plays silence or the wrong instruments. A sequence plays the bank's programs by the numbers its MIDI file used, so the bank needs programs with those numbers.
- A sound is off key. A tone plays its sample as recorded at its centre note. Give the note the sample was recorded at, middle C being 60. A very short sample sounds off key whatever the note (the FAQ).
The controller#
Pad.Pressed is true on the frame a button goes down and Held while it is down, so a menu that moves on Held moves every frame. A second controller is a Pad with Port 1. The library decodes only the standard controller.