//
// GPU Core
//
-// by cal2
+// Originally by David Raingeard (Cal2)
// GCC/SDL port by Niels Wagenaar (Linux/WIN32) and Caz (BeOS)
// Cleanups, endian wrongness, and bad ASM amelioration by James L. Hammons
// Note: Endian wrongness probably stems from the MAME origins of this emu and
//#define GPU_DEBUG
// For GPU dissasembly...
-/*
+
#define GPU_DIS_ABS
#define GPU_DIS_ADD
#define GPU_DIS_ADDC
#define REGPAGE 0x4000
#define DMAEN 0x8000
+// External global variables
+
+extern int start_logging;
+extern int gpu_start_log;
+
// Private function prototypes
void GPUUpdateRegisterBanks(void);
void GPUDumpRegisters(void);
void GPUDumpMemory(void);
-// External global variables
-
-extern int start_logging;
-extern int gpu_start_log;
-
static void gpu_opcode_add(void);
static void gpu_opcode_addc(void);
static void gpu_opcode_addq(void);
static void gpu_opcode_sat24(void);
static void gpu_opcode_pack(void);
-uint8 gpu_opcode_cycles[64] =
+// This is wrong, since it doesn't take pipeline effects into account. !!! FIX !!!
+/*uint8 gpu_opcode_cycles[64] =
{
3, 3, 3, 3, 3, 3, 3, 3,
3, 3, 3, 3, 3, 3, 3, 3,
5, 4, 5, 6, 6, 1, 1, 1,
1, 2, 2, 2, 1, 1, 9, 3,
3, 1, 6, 6, 2, 2, 3, 3
+};//*/
+//Here's a QnD kludge...
+//This is wrong, wrong, WRONG, but it seems to work for the time being...
+//(That is, it fixes Flip Out which relies on GPU timing rather than semaphores. Bad developers! Bad!)
+//What's needed here is a way to take pipeline effects into account (including pipeline stalls!)...
+uint8 gpu_opcode_cycles[64] =
+{
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 9, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 2,
+ 2, 2, 2, 3, 3, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 4, 1,
+ 1, 1, 3, 3, 1, 1, 1, 1
};
void (*gpu_opcode[64])()=
//
uint8 GPUReadByte(uint32 offset, uint32 who/*=UNKNOWN*/)
{
+ if (offset >= 0xF02000 && offset <= 0xF020FF)
+ WriteLog("GPU: ReadByte--Attempt to read from GPU register file by %s!\n", whoName[who]);
+
if ((offset >= GPU_WORK_RAM_BASE) && (offset < GPU_WORK_RAM_BASE+0x1000))
return gpu_ram_8[offset & 0xFFF];
else if ((offset >= GPU_CONTROL_RAM_BASE) && (offset < GPU_CONTROL_RAM_BASE+0x20))
//
uint16 GPUReadWord(uint32 offset, uint32 who/*=UNKNOWN*/)
{
+ if (offset >= 0xF02000 && offset <= 0xF020FF)
+ WriteLog("GPU: ReadWord--Attempt to read from GPU register file by %s!\n", whoName[who]);
+
if ((offset >= GPU_WORK_RAM_BASE) && (offset < GPU_WORK_RAM_BASE+0x1000))
{
offset &= 0xFFF;
return data >> 16;
}
-//TEMP--Mirror of F03000?
-if (offset >= 0xF0B000 && offset <= 0xF0BFFF)
-WriteLog("[GPUR16] --> Possible GPU RAM mirror access by %s!", whoName[who]);
+//TEMP--Mirror of F03000? No. Writes only...
+//if (offset >= 0xF0B000 && offset <= 0xF0BFFF)
+//WriteLog("[GPUR16] --> Possible GPU RAM mirror access by %s!", whoName[who]);
return JaguarReadWord(offset, who);
}
//
uint32 GPUReadLong(uint32 offset, uint32 who/*=UNKNOWN*/)
{
+ if (offset >= 0xF02000 && offset <= 0xF020FF)
+ WriteLog("GPU: ReadLong--Attempt to read from GPU register file by %s!\n", whoName[who]);
+
// if ((offset >= GPU_WORK_RAM_BASE) && (offset < GPU_WORK_RAM_BASE + 0x1000))
if ((offset >= GPU_WORK_RAM_BASE) && (offset <= GPU_WORK_RAM_BASE + 0x0FFC))
{
return 0;
}
}
-//TEMP--Mirror of F03000?
-if (offset >= 0xF0B000 && offset <= 0xF0BFFF)
- WriteLog("[GPUR32] --> Possible GPU RAM mirror access by %s!\n", whoName[who]);
+//TEMP--Mirror of F03000? No. Writes only...
+//if (offset >= 0xF0B000 && offset <= 0xF0BFFF)
+// WriteLog("[GPUR32] --> Possible GPU RAM mirror access by %s!\n", whoName[who]);
/*if (offset >= 0xF1D000 && offset <= 0xF1DFFF)
WriteLog("[GPUR32] --> Reading from Wavetable ROM!\n");//*/
//
void GPUWriteByte(uint32 offset, uint8 data, uint32 who/*=UNKNOWN*/)
{
+ if (offset >= 0xF02000 && offset <= 0xF020FF)
+ WriteLog("GPU: WriteByte--Attempt to write to GPU register file by %s!\n", whoName[who]);
+
if ((offset >= GPU_WORK_RAM_BASE) && (offset <= GPU_WORK_RAM_BASE + 0x0FFF))
{
gpu_ram_8[offset & 0xFFF] = data;
//
void GPUWriteWord(uint32 offset, uint16 data, uint32 who/*=UNKNOWN*/)
{
+ if (offset >= 0xF02000 && offset <= 0xF020FF)
+ WriteLog("GPU: WriteWord--Attempt to write to GPU register file by %s!\n", whoName[who]);
+
if ((offset >= GPU_WORK_RAM_BASE) && (offset <= GPU_WORK_RAM_BASE + 0x0FFE))
{
gpu_ram_8[offset & 0xFFF] = (data>>8) & 0xFF;
/* offset &= 0xFFF;
SET16(gpu_ram_8, offset, data);//*/
+/*if (offset >= 0xF03214 && offset < 0xF0321F)
+ WriteLog("GPU: Writing WORD (%04X) to GPU RAM (%08X)...\n", data, offset);//*/
+
+
//This is the same stupid worthless code that was in the DSP!!! AARRRGGGGHHHHH!!!!!!
/* if (!gpu_in_exec)
{
//
void GPUWriteLong(uint32 offset, uint32 data, uint32 who/*=UNKNOWN*/)
{
+ if (offset >= 0xF02000 && offset <= 0xF020FF)
+ WriteLog("GPU: WriteLong--Attempt to write to GPU register file by %s!\n", whoName[who]);
+
// if ((offset >= GPU_WORK_RAM_BASE) && (offset < GPU_WORK_RAM_BASE + 0x1000))
if ((offset >= GPU_WORK_RAM_BASE) && (offset <= GPU_WORK_RAM_BASE + 0x0FFC))
{
#ifdef GPU_DEBUG
if (offset & 0x03)
{
- WriteLog("GPU: Write32--unaligned write @ %08X [%08X]\n", offset, data);
+ WriteLog("GPU: Write32--unaligned write @ %08X [%08X] by %s\n", offset, data, whoName[who]);
GPUDumpRegisters();
}
#endif // GPU_DEBUG
gpu_matrix_control = data;
break;
case 0x08:
- // Can only point to long aligned addresses
+ // This can only point to long aligned addresses
gpu_pointer_to_matrix = data & 0xFFFFFFFC;
break;
case 0x0C:
{
//WriteLog("asked to perform a single step (single step is %senabled)\n",(data&0x8)?"":"not ");
}
-// gpu_control = (gpu_control & 0x107C0) | (data & (~0x107C0));
gpu_control = (gpu_control & 0xF7C0) | (data & (~0xF7C0));
// if gpu wasn't running but is now running, execute a few cycles
#endif // GPU_DEBUG
//if (GPU_RUNNING)
// GPUDumpDisassembly();
+/*if (GPU_RUNNING)
+{
+ if (gpu_pc == 0xF035D8)
+ {
+// GPUDumpDisassembly();
+// log_done();
+// exit(1);
+ gpu_control &= 0xFFFFFFFE; // Don't run it and let's see what happens!
+//Hmm. Seems to lock up when going into the demo...
+//Try to disable the collision altogether!
+ }
+}//*/
+extern int effect_start5;
+static bool finished = false;
+//if (GPU_RUNNING && effect_start5 && !finished)
+if (GPU_RUNNING && effect_start5 && gpu_pc == 0xF035D8)
+{
+ // Let's do a dump of $6528!
+/* uint32 numItems = JaguarReadWord(0x6BD6);
+ WriteLog("\nDump of $6528: %u items.\n\n", numItems);
+ for(int i=0; i<numItems*3*4; i+=3*4)
+ {
+ WriteLog("\t%04X: %08X %08X %08X -> ", 0x6528+i, JaguarReadLong(0x6528+i),
+ JaguarReadLong(0x6528+i+4), JaguarReadLong(0x6528+i+8));
+ uint16 link = JaguarReadWord(0x6528+i+8+2);
+ for(int j=0; j<40; j+=4)
+ WriteLog("%08X ", JaguarReadLong(link + j));
+ WriteLog("\n");
+ }
+ WriteLog("\n");//*/
+ // Let's try a manual blit here...
+//This isn't working the way it should! !!! FIX !!!
+//Err, actually, it is.
+// NOW, it works right! Problem solved!!! It's a blitter bug!
+/* uint32 src = 0x4D54, dst = 0xF03000, width = 10 * 4;
+ for(int y=0; y<127; y++)
+ {
+ for(int x=0; x<2; x++)
+ {
+ JaguarWriteLong(dst, JaguarReadLong(src));
+
+ src += 4;
+ dst += 4;
+ }
+ src += width - (2 * 4);
+ }//*/
+/* finished = true;
+ doGPUDis = true;
+ WriteLog("\nGPU: About to execute collision detection code.\n\n");//*/
+
+/* WriteLog("\nGPU: About to execute collision detection code. Data @ 4D54:\n\n");
+ int count = 0;
+ for(int i=0x004D54; i<0x004D54+2048; i++)
+ {
+ WriteLog("%02X ", JaguarReadByte(i));
+ count++;
+ if (count == 32)
+ {
+ count = 0;
+ WriteLog("\n");
+ }
+ }
+ WriteLog("\n\nData @ F03000:\n\n");
+ count = 0;
+ for(int i=0xF03000; i<0xF03200; i++)
+ {
+ WriteLog("%02X ", JaguarReadByte(i));
+ count++;
+ if (count == 32)
+ {
+ count = 0;
+ WriteLog("\n");
+ }
+ }
+ WriteLog("\n\n");
+ log_done();
+ exit(0);//*/
+}
+//if (!GPU_RUNNING)
+// doGPUDis = false;
+/*if (!GPU_RUNNING && finished)
+{
+ WriteLog("\nGPU: Finished collision detection code. Exiting!\n\n");
+ GPUDumpRegisters();
+ log_done();
+ exit(0);
+}//*/
// (?) If we're set running by the M68K (or DSP?) then end its timeslice to
// allow the GPU a chance to run...
// Yes! This partially fixed Trevor McFur...
void gpu_done(void)
{
- WriteLog("GPU: stopped at PC=%08X (GPU %s running)\n", (unsigned int)gpu_pc, GPU_RUNNING ? "was" : "wasn't");
+ WriteLog("GPU: Stopped at PC=%08X (GPU %s running)\n", (unsigned int)gpu_pc, GPU_RUNNING ? "was" : "wasn't");
// Get the interrupt latch & enable bits
uint8 bits = (gpu_control >> 6) & 0x1F, mask = (gpu_flags >> 4) & 0x1F;
GPUDumpRegisters();
GPUDumpDisassembly();
-/* WriteLog("---[GPU code at %08X]---------------------------\n", gpu_pc);
- j = gpu_pc - 64;
- for(int i=0; i<4096; i++)
- {
- uint32 oldj = j;
- j += dasmjag(JAGUAR_GPU, buffer, j);
- WriteLog("\t%08X: %s\n", oldj, buffer);
- }*/
-
WriteLog("\nGPU opcodes use:\n");
for(int i=0; i<64; i++)
{
WriteLog("(RM=%08X, RN=%08X)\n", RM, RN);//*/
if ((gpu_pc < 0xF03000 || gpu_pc > 0xF03FFF) && !tripwire)
{
- WriteLog("GPU: Executing outside local RAM!\n");
+ WriteLog("GPU: Executing outside local RAM! GPU_PC: %08X\n", gpu_pc);
tripwire = true;
}
}
UINT32 res = RN - RM - gpu_flag_c;
UINT32 borrow = gpu_flag_c;
// SET_ZNC_SUB(RN, RM, res); //???BUG??? YES!!!
- SET_ZNC_SUB(RN - borrow, RM, res);
+//No matter how you do it, there is a problem. With below, it's 0-0 with carry,
+//and the one below it it's FFFFFFFF - FFFFFFFF with carry... !!! FIX !!!
+// SET_ZNC_SUB(RN - borrow, RM, res);
+ SET_ZNC_SUB(RN, RM + borrow, res);
RN = res;
#ifdef GPU_DIS_SUBC
if (doGPUDis)
WriteLog("[NCZ:%u%u%u, R%02u=%08X, R%02u=%08X]\n", gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN);
#endif
}
+/*
+N = 5, M = 3, 3 - 5 = -2, C = 1... Or, in our case:
+N = 0, M = 1, 0 - 1 = -1, C = 0!
+#define SET_C_SUB(a,b) (gpu_flag_c = ((UINT32)(b) > (UINT32)(a)))
+#define SET_ZN(r) SET_N(r); SET_Z(r)
+#define SET_ZNC_ADD(a,b,r) SET_N(r); SET_Z(r); SET_C_ADD(a,b)
+#define SET_ZNC_SUB(a,b,r) SET_N(r); SET_Z(r); SET_C_SUB(a,b)
+*/
static void gpu_opcode_subq(void)
{
#ifdef GPU_DIS_SUBQ
{
#ifdef GPU_DIS_MOVEPC
if (doGPUDis)
- WriteLog("%06X: MOVE PC, R%02u [NCZ:%u%u%u, PC=%08X, R%02u=%08X] -> ", gpu_pc-2, IMM_1, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, gpu_pc-2, IMM_2, RN);
+ WriteLog("%06X: MOVE PC, R%02u [NCZ:%u%u%u, PC=%08X, R%02u=%08X] -> ", gpu_pc-2, IMM_2, gpu_flag_n, gpu_flag_c, gpu_flag_z, gpu_pc-2, IMM_2, RN);
#endif
// Should be previous PC--this might not always be previous instruction!
// Then again, this will point right at the *current* instruction, i.e., MOVE PC,R!