X-Git-Url: http://shamusworld.gotdns.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=src%2Fgpu.cpp;h=681cbcf1fa558c1fa53fdb70f0ce6ab06bf12c7a;hb=73ca0f1c81b606de50838deb1e464cc95a1e15cc;hp=f7951ccc7d932332510ca3d4c868de253669f4f5;hpb=67a5f1a40072983cf87ae2093ca95c271d14e706;p=virtualjaguar diff --git a/src/gpu.cpp b/src/gpu.cpp index f7951cc..681cbcf 100644 --- a/src/gpu.cpp +++ b/src/gpu.cpp @@ -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 @@ -17,7 +17,7 @@ //#define GPU_DEBUG // For GPU dissasembly... -/* + #define GPU_DIS_ABS #define GPU_DIS_ADD #define GPU_DIS_ADDC @@ -145,6 +145,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 +158,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 +223,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,6 +234,21 @@ 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 }; void (*gpu_opcode[64])()= @@ -384,6 +400,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 +427,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 +451,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 +463,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 +509,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 +523,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 +564,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 +574,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 +636,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 +685,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 +733,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 +760,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 ", 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 +869,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 +957,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 +1057,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 +1066,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 +1075,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 +1103,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 +1273,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 +1511,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 +1650,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!