]> Shamusworld >> Repos - virtualjaguar/blobdiff - src/gpu.cpp
Kludge to allow games that read HC in TOM to work
[virtualjaguar] / src / gpu.cpp
index f7951ccc7d932332510ca3d4c868de253669f4f5..4729126928d99b4f1e3f2c4eb941b79d5194afcb 100644 (file)
@@ -1,7 +1,7 @@
 //
 // 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
 // Same problem with ADDC...
 //
 
+#include <stdlib.h>
 #include "gpu.h"
 
 //#define GPU_DEBUG
 
 // For GPU dissasembly...
-/*
+
 #define GPU_DIS_ABS
 #define GPU_DIS_ADD
 #define GPU_DIS_ADDC
@@ -145,6 +146,11 @@ GPU opcodes use (BIOS flying ATARI logo):
 #define REGPAGE                        0x4000
 #define DMAEN                  0x8000
 
+// External global variables
+
+extern int start_logging;
+extern int gpu_start_log;
+
 // Private function prototypes
 
 void GPUUpdateRegisterBanks(void);
@@ -153,11 +159,6 @@ void GPUDumpDisassembly(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);
@@ -223,7 +224,8 @@ static void gpu_opcode_store_r15_ri(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,
@@ -233,7 +235,33 @@ uint8 gpu_opcode_cycles[64] =
        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
+};//*/
+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,  1,  1,  1,
+       1,  1,  1,  1,  1,  1,  1,  1,
+       1,  1,  1,  1,  1,  1,  1,  1,
+       1,  1,  1,  1,  1,  1,  1,  1,
+       1,  1,  1,  1,  1,  1,  1,  1,
+       1,  1,  1,  1,  1,  1,  1,  1
+};//*/
 
 void (*gpu_opcode[64])()= 
 {      
@@ -384,6 +412,9 @@ void build_branch_condition_table(void)
 //
 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))
@@ -408,6 +439,9 @@ uint8 GPUReadByte(uint32 offset, uint32 who/*=UNKNOWN*/)
 //
 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;
@@ -429,9 +463,9 @@ uint16 GPUReadWord(uint32 offset, uint32 who/*=UNKNOWN*/)
                        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);
 }
@@ -441,6 +475,9 @@ WriteLog("[GPUR16] --> Possible GPU RAM mirror access by %s!", whoName[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))
        {
@@ -484,9 +521,9 @@ uint32 GPUReadLong(uint32 offset, uint32 who/*=UNKNOWN*/)
                        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");//*/
 
@@ -498,6 +535,9 @@ if (offset >= 0xF0B000 && offset <= 0xF0BFFF)
 //
 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;
@@ -536,6 +576,9 @@ void GPUWriteByte(uint32 offset, uint8 data, uint32 who/*=UNKNOWN*/)
 //
 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;
@@ -543,6 +586,10 @@ void GPUWriteWord(uint32 offset, uint16 data, uint32 who/*=UNKNOWN*/)
 /*             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)
                {
@@ -601,23 +648,22 @@ void GPUWriteWord(uint32 offset, uint16 data, uint32 who/*=UNKNOWN*/)
 //
 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_ram_8[offset & 0xFFF] = (data >> 24) & 0xFF,
-               gpu_ram_8[(offset+1) & 0xFFF] = (data >> 16) & 0xFF,
-               gpu_ram_8[(offset+2) & 0xFFF] = (data >> 8) & 0xFF,
-               gpu_ram_8[(offset+3) & 0xFFF] = data & 0xFF;//*/
                offset &= 0xFFF;
-               SET32(gpu_ram_8, offset, data);//*/
+               SET32(gpu_ram_8, offset, data);
                return;
        }
 //     else if ((offset >= GPU_CONTROL_RAM_BASE) && (offset < GPU_CONTROL_RAM_BASE+0x20))
@@ -651,7 +697,7 @@ void GPUWriteLong(uint32 offset, uint32 data, uint32 who/*=UNKNOWN*/)
                        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:
@@ -699,7 +745,6 @@ WriteLog("GPU: %s setting GPU PC to %08X %s\n", whoName[who], gpu_pc, (GPU_RUNNI
                        {
                                //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
@@ -727,6 +772,93 @@ WriteLog("\n");
 #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...
@@ -749,6 +881,7 @@ WriteLog("\n");
 
 //     JaguarWriteWord(offset, (data >> 16) & 0xFFFF, who);
 //     JaguarWriteWord(offset+2, data & 0xFFFF, who);
+// We're a 32-bit processor, we can do a long write...!
        JaguarWriteLong(offset, data, who);
 }
 
@@ -836,8 +969,6 @@ void GPUSetIRQLine(int irqline, int state)
 void gpu_init(void)
 {
        memory_malloc_secure((void **)&gpu_ram_8, 0x1000, "GPU work RAM");
-//     memory_malloc_secure((void **)&gpu_reg, 32*sizeof(int32), "GPU bank 0 regs");
-//     memory_malloc_secure((void **)&gpu_alternate_reg, 32*sizeof(int32), "GPU bank 1 regs");
        memory_malloc_secure((void **)&gpu_reg_bank_0, 32 * sizeof(int32), "GPU bank 0 regs");
        memory_malloc_secure((void **)&gpu_reg_bank_1, 32 * sizeof(int32), "GPU bank 1 regs");
 
@@ -938,7 +1069,7 @@ void GPUDumpMemory(void)
 
 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;
@@ -947,15 +1078,6 @@ void gpu_done(void)
        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++)
        {
@@ -965,6 +1087,8 @@ void gpu_done(void)
        WriteLog("\n");
 
        memory_free(gpu_ram_8);
+       memory_free(gpu_reg_bank_0);
+       memory_free(gpu_reg_bank_1);
 }
 
 //
@@ -991,6 +1115,35 @@ void gpu_exec(int32 cycles)
 
        while (cycles > 0 && GPU_RUNNING)
        {
+if (gpu_ram_8[0x054] == 0x98 && gpu_ram_8[0x055] == 0x0A && gpu_ram_8[0x056] == 0x03
+       && gpu_ram_8[0x057] == 0x00 && gpu_ram_8[0x058] == 0x00 && gpu_ram_8[0x059] == 0x00)
+{
+       if (gpu_pc == 0xF03000)
+       {
+               extern uint32 starCount;
+               starCount = 0;
+/*             WriteLog("GPU: Starting starfield generator... Dump of [R03=%08X]:\n", gpu_reg_bank_0[03]);
+               uint32 base = gpu_reg_bank_0[3];
+               for(uint32 i=0; i<0x100; i+=16)
+               {
+                       WriteLog("%02X: ", i);
+                       for(uint32 j=0; j<16; j++)
+                       {
+                               WriteLog("%02X ", JaguarReadByte(base + i + j));
+                       }
+                       WriteLog("\n");
+               }*/
+       }
+//     if (gpu_pc == 0xF03)
+       {
+       }
+}//*/
+/*if (gpu_pc == 0xF03B9E && gpu_reg_bank_0[01] == 0)
+{
+       GPUDumpRegisters();
+       WriteLog("GPU: Starting disassembly log...\n");
+       doGPUDis = true;
+}//*/
 /*if (gpu_pc == 0xF0359A)
 {
        doGPUDis = true;
@@ -1132,7 +1285,7 @@ if (gpu_start_log)
        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;
 }
        }
@@ -1370,14 +1523,25 @@ static void gpu_opcode_subc(void)
        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
@@ -1498,7 +1662,7 @@ static void gpu_opcode_move_pc(void)
 {
 #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!