+ HW_GPU_STATUS = SWAP32(0x10802000);
+ psxHwReadGpuSRptr = Config.hacks.gpu_busy
+ ? psxHwReadGpuSRbusyHack : psxHwReadGpuSR;
+}
+
+void psxHwWriteIstat(u32 value)
+{
+ u32 stat = psxHu16(0x1070) & value;
+ psxHu16ref(0x1070) = SWAPu16(stat);
+
+ psxRegs.CP0.n.Cause &= ~0x400;
+ if (stat & psxHu16(0x1074))
+ psxRegs.CP0.n.Cause |= 0x400;
+}
+
+void psxHwWriteImask(u32 value)
+{
+ u32 stat = psxHu16(0x1070);
+ psxHu16ref(0x1074) = SWAPu16(value);
+ if (stat & value) {
+ //if ((psxRegs.CP0.n.SR & 0x401) == 0x401)
+ // log_unhandled("irq on unmask @%08x\n", psxRegs.pc);
+ set_event(PSXINT_NEWDRC_CHECK, 1);
+ }
+ psxRegs.CP0.n.Cause &= ~0x400;
+ if (stat & value)
+ psxRegs.CP0.n.Cause |= 0x400;
+}
+
+void psxHwWriteDmaIcr32(u32 value)
+{
+ u32 tmp = value & 0x00ff803f;
+ tmp |= (SWAPu32(HW_DMA_ICR) & ~value) & 0x7f000000;
+ if ((tmp & HW_DMA_ICR_GLOBAL_ENABLE && tmp & 0x7f000000)
+ || tmp & HW_DMA_ICR_BUS_ERROR) {
+ if (!(SWAPu32(HW_DMA_ICR) & HW_DMA_ICR_IRQ_SENT))
+ psxHu32ref(0x1070) |= SWAP32(8);
+ tmp |= HW_DMA_ICR_IRQ_SENT;
+ }
+ HW_DMA_ICR = SWAPu32(tmp);
+}
+
+void psxHwWriteGpuSR(u32 value)
+{
+ u32 old_sr = HW_GPU_STATUS, new_sr;
+ GPU_writeStatus(value);
+ gpuSyncPluginSR();
+ new_sr = HW_GPU_STATUS;
+ // "The Next Tetris" seems to rely on the field order after enable
+ if ((old_sr ^ new_sr) & new_sr & SWAP32(PSXGPU_ILACE))
+ frame_counter |= 1;
+}
+
+u32 psxHwReadGpuSR(void)
+{
+ u32 v, c = psxRegs.cycle;
+
+ // meh2, syncing for img bit, might want to avoid it..
+ gpuSyncPluginSR();
+ v = SWAP32(HW_GPU_STATUS);
+ v |= ((s32)(psxRegs.gpuIdleAfter - c) >> 31) & PSXGPU_nBUSY;
+
+ // XXX: because of large timeslices can't use hSyncCount, using rough
+ // approximization instead. Perhaps better use hcounter code here or something.
+ if (hSyncCount < 240 && (v & PSXGPU_ILACE_BITS) != PSXGPU_ILACE_BITS)
+ v |= PSXGPU_LCF & (c << 20);
+ return v;
+}
+
+// a hack due to poor timing of gpu idle bit
+// to get rid of this, GPU draw times, DMAs, cpu timing has to fall within
+// certain timing window or else games like "ToHeart" softlock
+u32 psxHwReadGpuSRbusyHack(void)
+{
+ u32 v = psxHwReadGpuSR();
+ static u32 hack;
+ if (!(hack++ & 3))
+ v &= ~PSXGPU_nBUSY;
+ return v;