diff options
Diffstat (limited to 'PcsxSrc/PsxCounters.c')
-rw-r--r-- | PcsxSrc/PsxCounters.c | 202 |
1 files changed, 202 insertions, 0 deletions
diff --git a/PcsxSrc/PsxCounters.c b/PcsxSrc/PsxCounters.c new file mode 100644 index 0000000..a9bdabf --- /dev/null +++ b/PcsxSrc/PsxCounters.c @@ -0,0 +1,202 @@ +/* Pcsx - Pc Psx Emulator
+ * Copyright (C) 1999-2002 Pcsx Team
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <string.h>
+
+#include "PsxCommon.h"
+
+static int cnts = 4;
+
+static void psxRcntUpd(unsigned long index) {
+ psxCounters[index].sCycle = psxRegs.cycle;
+ if ((!(psxCounters[index].mode & 1)) || (index!=2)) {
+ if (psxCounters[index].mode & 0x08) { // Count to target
+ psxCounters[index].Cycle = ((psxCounters[index].target - psxCounters[index].count) * psxCounters[index].rate) / BIAS;
+ }
+ else { // Count to 0xffff
+ psxCounters[index].Cycle = ((0xffff - psxCounters[index].count) * psxCounters[index].rate) / BIAS;
+ }
+ } else psxCounters[index].Cycle = 0xffffffff;
+}
+
+static void psxRcntReset(unsigned long index) {
+ psxCounters[index].count = 0;
+ psxRcntUpd(index);
+
+ if ((psxCounters[index].mode & 0x50) == 0x50) psxHu32(0x1070)|= psxCounters[index].interrupt;
+}
+
+static void psxRcntSet() {
+ int i;
+
+ psxNextCounter = 0x7fffffff;
+ psxNextsCounter = psxRegs.cycle;
+
+ for (i=0; i<cnts; i++) {
+ long count = psxCounters[i].Cycle - (psxRegs.cycle - psxCounters[i].sCycle);
+
+ if (count < 0) {
+ psxNextCounter = 0; break;
+ }
+
+ if (count < (long)psxNextCounter) {
+ psxNextCounter = count;
+ }
+ }
+}
+
+void psxRcntInit() {
+
+ memset(psxCounters, 0, sizeof(psxCounters));
+
+ psxCounters[0].rate = 1; psxCounters[0].interrupt = 16;
+ psxCounters[1].rate = 1; psxCounters[1].interrupt = 32;
+ psxCounters[2].rate = 1; psxCounters[2].interrupt = 64;
+
+ psxCounters[3].interrupt = 1;
+ psxCounters[3].mode = 0x58; // The VSync counter mode
+ psxCounters[3].target = 1;
+ UpdateVSyncRate();
+
+ if (SPU_update != NULL) {
+ cnts = 5;
+
+ if (Config.PsxType)
+ psxCounters[4].rate = (262 / 32) * 50; // pal
+ else
+ psxCounters[4].rate = (312 / 32) * 60; // ntsc
+ psxCounters[4].target = 1;
+ psxCounters[4].mode = 0x8;
+ } else if (SPU_async != NULL) {
+ cnts = 5;
+
+ psxCounters[4].rate = 768 * 64;
+ psxCounters[4].target = 1;
+ psxCounters[4].mode = 0x8;
+ } else cnts = 4;
+
+ psxRcntUpd(0); psxRcntUpd(1); psxRcntUpd(2); psxRcntUpd(3);
+ psxRcntSet();
+}
+
+void UpdateVSyncRate() {
+ if (Config.PsxType) // ntsc - 0 | pal - 1
+ psxCounters[3].rate = (PSXCLK / 50);// / BIAS;
+ else psxCounters[3].rate = (PSXCLK / 60);// / BIAS;
+}
+
+void psxRcntUpdate() {
+ if ((psxRegs.cycle - psxCounters[3].sCycle) >= psxCounters[3].Cycle) {
+ psxRcntReset(3);
+ GPU_updateLace(); // updateGPU
+ SysUpdate();
+#ifdef GTE_LOG
+ GTE_LOG("VSync\n");
+#endif
+ }
+
+ if ((psxRegs.cycle - psxCounters[0].sCycle) >= psxCounters[0].Cycle) {
+ psxRcntReset(0);
+ }
+
+ if ((psxRegs.cycle - psxCounters[1].sCycle) >= psxCounters[1].Cycle) {
+ psxRcntReset(1);
+ }
+
+ if ((psxRegs.cycle - psxCounters[2].sCycle) >= psxCounters[2].Cycle) {
+ psxRcntReset(2);
+ }
+
+ if (cnts >= 5) {
+ if ((psxRegs.cycle - psxCounters[4].sCycle) >= psxCounters[4].Cycle) {
+ if (SPU_update != NULL)
+ SPU_update();
+ if (SPU_async != NULL)
+ SPU_async((psxRegs.cycle - psxCounters[4].sCycle) * BIAS);
+ psxRcntReset(4);
+ }
+ }
+
+ psxRcntSet();
+}
+
+void psxRcntWcount(unsigned long index, unsigned long value) {
+// SysPrintf("writeCcount[%d] = %x\n", index, value);
+// PSXCPU_LOG("writeCcount[%d] = %x\n", index, value);
+ psxCounters[index].count = value;
+ psxRcntUpd(index);
+ psxRcntSet();
+}
+
+void psxRcntWmode(unsigned long index, unsigned long value) {
+// SysPrintf("writeCmode[%ld] = %lx\n", index, value);
+ psxCounters[index].mode = value;
+ if(index == 0) {
+ switch (value & 0x300) {
+ case 0x100:
+ psxCounters[index].rate = ((psxCounters[3].rate /** BIAS*/) / 386) / 262; // seems ok
+ break;
+ default:
+ psxCounters[index].rate = 1;
+ }
+ }
+ else if(index == 1) {
+ switch (value & 0x300) {
+ case 0x100:
+ psxCounters[index].rate = (psxCounters[3].rate /** BIAS*/) / 262; // seems ok
+ break;
+ default:
+ psxCounters[index].rate = 1;
+ }
+ }
+ else if(index == 2) {
+ switch (value & 0x300) {
+ case 0x200:
+ psxCounters[index].rate = 8; // 1/8 speed
+ break;
+ default:
+ psxCounters[index].rate = 1; // normal speed
+ }
+ }
+
+ // Need to set a rate and target
+ psxRcntUpd(index);
+ psxRcntSet();
+}
+
+void psxRcntWtarget(unsigned long index, unsigned long value) {
+// SysPrintf("writeCtarget[%ld] = %lx\n", index, value);
+ psxCounters[index].target = value;
+ psxRcntUpd(index);
+ psxRcntSet();
+}
+
+unsigned long psxRcntRcount(unsigned long index) {
+// if ((!(psxCounters[index].mode & 1)) || (index!=2)) {
+ return (psxCounters[index].count + BIAS * (psxRegs.cycle - psxCounters[index].sCycle) / psxCounters[index].rate) & 0xffff;
+// } else return 0;
+}
+
+int psxRcntFreeze(gzFile f, int Mode) {
+ char Unused[4096 - sizeof(psxCounter)];
+
+ gzfreezel(psxCounters);
+ gzfreezel(Unused);
+
+ return 0;
+}
|