How the Real3D configuration registers (0x9C) work

By studying the Real3D library files in Ghidra, I've figured out what the Real3D configuration registers actually do.
(g_API_Data + 0x518) points to _pingpong_size, (g_API_Data + 0x51c) points to _update_size, and (g_API_Data + 0x7e0) points to _offline_mode.
0x9C000000 is the size of the ping pong buffer (high culling RAM) in 32-bit words. 0x9C000008 is the combined size of the ping pong buffer and the update buffer in 32-bit words. Notably, all games leave a gap at the start of low culling RAM twice as large as the combined size of the ping pong and update buffers; it seems that both of these are double-buffered. For example, Scud Race sets 0x9C000008 to 0x18000 (0x60000 bytes), and never writes to low culling RAM lower than 0x8C0C0000. The update buffer is probably used to store updated polygon and texture data while the Real3D Pro-1000 is busy rendering, and then updates the polygon RAM and texture RAM (perhaps even low culling RAM?) when it has finished rendering the frame.
0x9C000004 specifies a bunch of flags, but the only one that varies at all across games is _offline_mode; the PC does not send data to the Pro-1000 in offline mode. All games except for Sega Rally 2 and Star Wars Trilogy Arcade have this flag enabled, so I'm guessing it only affects receiving data from a PC via SCSI and does not affect data sent internally.
Well that's another little mystery solved
- Code: Select all
local_118 = 0;
local_14c = *(int *)(g_API_Data + 0x518) + *(int *)(g_API_Data + 0x51c) >> 2; // _pingpong_size + _update_size
local_11c = *(int *)(g_API_Data + 0x518) >> 2; // _pingpong_size
if ((*(uint *)(g_API_Data + 0x7e0) >> 1 & 1) != 0) {
local_118 = 4;
local_14c = local_14c + 4;
local_11c = local_11c + 4;
}
if ((*(uint *)(g_API_Data + 0x7e0) >> 1 & 1) == 0) {
local_1c = local_11c; // 0x9c000000
local_18 = local_118; // 0x9c000004
local_14 = local_14c; // 0x9c000008
_PRO_IO(&local_e0,0x31,local_118 << 2 | 0x8c000000,0xffffffff,0);
_PRO_IO(local_110,0xc,local_118 * 4 + 0xc4U | 0x8c000000,0xffffffff,0);
_PRO_IO(local_13c,8,0x8c0000f4,0xffffffff,0);
_PRO_IO(&local_e0,0x31,local_14c << 2 | 0x8c000000,0xffffffff,0);
_PRO_IO(local_110,0xc,local_14c * 4 + 0xc4U | 0x8c000000,0xffffffff,0);
_PRO_IO(local_13c,8,(local_14c + 0x3d) * 4 | 0x8c000000,0xffffffff,0);
_PRO_Flush();
_PRO_IO(&local_1c,3,0x9c000000,0xffffffff,0);
_PRO_Flush();
}
(g_API_Data + 0x518) points to _pingpong_size, (g_API_Data + 0x51c) points to _update_size, and (g_API_Data + 0x7e0) points to _offline_mode.
0x9C000000 is the size of the ping pong buffer (high culling RAM) in 32-bit words. 0x9C000008 is the combined size of the ping pong buffer and the update buffer in 32-bit words. Notably, all games leave a gap at the start of low culling RAM twice as large as the combined size of the ping pong and update buffers; it seems that both of these are double-buffered. For example, Scud Race sets 0x9C000008 to 0x18000 (0x60000 bytes), and never writes to low culling RAM lower than 0x8C0C0000. The update buffer is probably used to store updated polygon and texture data while the Real3D Pro-1000 is busy rendering, and then updates the polygon RAM and texture RAM (perhaps even low culling RAM?) when it has finished rendering the frame.
0x9C000004 specifies a bunch of flags, but the only one that varies at all across games is _offline_mode; the PC does not send data to the Pro-1000 in offline mode. All games except for Sega Rally 2 and Star Wars Trilogy Arcade have this flag enabled, so I'm guessing it only affects receiving data from a PC via SCSI and does not affect data sent internally.
Well that's another little mystery solved
