static uint32_t gpu_data_organization;
static uint32_t gpu_control;
static uint32_t gpu_div_control;
-// There is a distinct advantage to having these separated out--there's no need to clear
-// a bit before writing a result. I.e., if the result of an operation leaves a zero in
-// the carry flag, you don't have to zero gpu_flag_c before you can write that zero!
+// There is a distinct advantage to having these separated out--there's no need
+// to clear a bit before writing a result. I.e., if the result of an operation
+// leaves a zero in the carry flag, you don't have to zero gpu_flag_c before
+// you can write that zero!
static uint8_t gpu_flag_z, gpu_flag_n, gpu_flag_c;
uint32_t gpu_reg_bank_0[32];
uint32_t gpu_reg_bank_1[32];
*((uint32_t *)(&gpu_ram_8[i])) = rand();
}
+
uint32_t GPUReadPC(void)
{
return gpu_pc;
}
+
void GPUResetStats(void)
{
for(uint32_t i=0; i<64; i++)
WriteLog("--> GPU stats were reset!\n");
}
+
void GPUDumpDisassembly(void)
{
char buffer[512];
}
}
+
void GPUDumpRegisters(void)
{
WriteLog("\n---[GPU flags: NCZ %d%d%d]-----------------------\n", gpu_flag_n, gpu_flag_c, gpu_flag_z);
}
}
+
void GPUDumpMemory(void)
{
WriteLog("\n---[GPU data at 00F03000]---------------------------\n");
gpu_ram_8[i+1], gpu_ram_8[i+2], gpu_ram_8[i+3]);
}
+
void GPUDone(void)
{
+ WriteLog("\n\n---------------------------------------------------------------------\n");
+ WriteLog("GPU I/O Registers\n");
+ WriteLog("---------------------------------------------------------------------\n");
+ WriteLog("F0%04X (G_FLAGS): $%06X\n", 0x2100, (gpu_flags & 0xFFFFFFF8) | (gpu_flag_n << 2) | (gpu_flag_c << 1) | gpu_flag_z);
+ WriteLog("F0%04X (G_MTXC): $%04X\n", 0x2104, gpu_matrix_control);
+ WriteLog("F0%04X (G_MTXA): $%04X\n", 0x2108, gpu_pointer_to_matrix);
+ WriteLog("F0%04X (G_END): $%02X\n", 0x210C, gpu_data_organization);
+ WriteLog("F0%04X (G_PC): $%06X\n", 0x2110, gpu_pc);
+ WriteLog("F0%04X (G_CTRL): $%06X\n", 0x2114, gpu_control);
+ WriteLog("F0%04X (G_HIDATA): $%08X\n", 0x2118, gpu_hidata);
+ WriteLog("F0%04X (G_REMAIN): $%08X\n", 0x211C, gpu_remain);
+ WriteLog("F0%04X (G_DIVCTRL): $%02X\n", 0x211C, gpu_div_control);
+ WriteLog("---------------------------------------------------------------------\n\n\n");
+
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
WriteLog("\t%17s %lu\n", gpu_opcode_str[i], gpu_opcode_use[i]);
}
WriteLog("\n");
-
-// memory_free(gpu_ram_8);
-// memory_free(gpu_reg_bank_0);
-// memory_free(gpu_reg_bank_1);
}
+
//
// Main GPU execution core
//
if (doGPUDis)
WriteLog("%06X: DIV R%02u, R%02u (%s) [NCZ:%u%u%u, R%02u=%08X, R%02u=%08X] -> ", gpu_pc-2, IMM_1, IMM_2, (gpu_div_control & 0x01 ? "16.16" : "32"), gpu_flag_n, gpu_flag_c, gpu_flag_z, IMM_1, RM, IMM_2, RN);
#endif
-// NOTE: remainder is NOT calculated correctly here!
-// The original tried to get it right by checking to see if the
-// remainder was negative, but that's too late...
-// The code there should do it now, but I'm not 100% sure...
-// [Now it should be correct, but not displaying correct behavior of the actual
-// hardware. A step in the right direction.]
-
+#if 0
if (RM)
{
if (gpu_div_control & 0x01) // 16.16 division
gpu_remain = RN % RM;
RN = RN / RM;
}
-
-// What we really should do here is figure out why this condition
-// happens in the real divide unit and emulate *that* behavior.
-#if 0
- if ((gpu_remain - RM) & 0x80000000) // If the result would have been negative...
- gpu_remain -= RM; // Then make it negative!
-#endif
}
else
+ {
+ // This is what happens according to SCPCD. NYAN!
RN = 0xFFFFFFFF;
+ gpu_remain = 0;
+ }
+#else
+ // Real algorithm, courtesy of SCPCD: NYAN!
+ uint32_t q = RN;
+ uint32_t r = 0;
+
+ // If 16.16 division, stuff top 16 bits of RN into remainder and put the
+ // bottom 16 of RN in top 16 of quotient
+ if (gpu_div_control & 0x01)
+ q <<= 16, r = RN >> 16;
+
+ for(int i=0; i<32; i++)
+ {
+// uint32_t sign = (r >> 31) & 0x01;
+ uint32_t sign = r & 0x80000000;
+ r = (r << 1) | ((q >> 31) & 0x01);
+ r += (sign ? RM : -RM);
+ q = (q << 1) | (((~r) >> 31) & 0x01);
+ }
+
+ RN = q;
+ gpu_remain = r;
+#endif
#ifdef GPU_DIS_DIV
if (doGPUDis)