void psxRcnt0Wmode(u32 value) { PSXCNT_LOG("IOP Counter[0] writeMode = %lx\n", value); psxCounters[0].mode = value; psxCounters[0].mode|= 0x0400; psxCounters[0].rate = 1; if(value & IOPCNT_ALT_SOURCE) psxCounters[0].rate = PSXPIXEL; if(psxCounters[0].mode & IOPCNT_ENABLE_GATE) { // gated counters are added up as per the h/vblank timers. PSXCNT_LOG("IOP Counter[0] Gate Check set, value = %x\n", value); psxhblankgate |= 1; } else psxhblankgate &= ~1; psxCounters[0].count = 0; psxCounters[0].sCycleT = psxRegs.cycle; psxCounters[0].target &= 0xffff; _rcntSet( 0 ); }
__fi void psxRcntWmode16( int index, u32 value ) { PSXCNT_LOG( "IOP Counter[%d] writeMode = 0x%04X", index, value ); pxAssume( index >= 0 && index < 3 ); psxCounter& counter = psxCounters[index]; counter.mode = value; counter.mode |= 0x0400; if( index == 2 ) { switch(value & 0x200) { case 0x000: psxCounters[2].rate = 1; break; case 0x200: psxCounters[2].rate = 8; break; jNO_DEFAULT; } if((counter.mode & 0x7) == 0x7 || (counter.mode & 0x7) == 0x1) { counter.mode |= IOPCNT_STOPPED; } } else { // Counters 0 and 1 can select PIXEL or HSYNC as an alternate source: counter.rate = 1; if(value & IOPCNT_ALT_SOURCE) counter.rate = (index==0) ? PSXPIXEL : PSXHBLANK; if(counter.mode & IOPCNT_ENABLE_GATE) { // gated counters are added up as per the h/vblank timers. // (the PIXEL alt source becomes a vsync gate) counter.mode |= IOPCNT_STOPPED; PSXCNT_LOG( "IOP Counter[%d] Gate Check set, value = 0x%04X", index, value ); if( index == 0 ) psxhblankgate |= 1; // fixme: these gate flags should be one var >_< else psxvblankgate |= 1<<1; } else { if( index == 0 ) psxhblankgate &= ~1; else psxvblankgate &= ~(1<<1); } } counter.count = 0; counter.sCycleT = psxRegs.cycle; counter.target &= 0xffff; _rcntSet( index ); }
__fi void psxRcntWmode32( int index, u32 value ) { PSXCNT_LOG( "IOP Counter[%d] writeMode = 0x%04x", index, value ); pxAssume( index >= 3 && index < 6 ); psxCounter& counter = psxCounters[index]; counter.mode = value; counter.mode |= 0x0400; if( index == 3 ) { // Counter 3 has the HBlank as an alternate source. counter.rate = 1; if(value & IOPCNT_ALT_SOURCE) counter.rate = PSXHBLANK; if(counter.mode & IOPCNT_ENABLE_GATE) { PSXCNT_LOG("IOP Counter[3] Gate Check set, value = %x", value); counter.mode |= IOPCNT_STOPPED; psxvblankgate |= 1<<3; } else psxvblankgate &= ~(1<<3); } else { switch(value & 0x6000) { case 0x0000: counter.rate = 1; break; case 0x2000: counter.rate = 8; break; case 0x4000: counter.rate = 16; break; case 0x6000: counter.rate = 256; break; } // Need to set a rate and target if((counter.mode & 0x7) == 0x7 || (counter.mode & 0x7) == 0x1) { Console.WriteLn( "Gate set on IOP Counter %d, disabling", index ); counter.mode |= IOPCNT_STOPPED; } } counter.count = 0; counter.sCycleT = psxRegs.cycle; counter.target &= 0xffffffff; _rcntSet( index ); }
void psxRcnt5Wmode(u32 value) { PSXCNT_LOG("IOP Counter[5] writeMode = %lx\n", value); psxCounters[5].mode = value; psxCounters[5].mode|= 0x0400; switch(value & 0x6000) { case 0x0000: psxCounters[5].rate = 1; break; case 0x2000: psxCounters[5].rate = 8; break; case 0x4000: psxCounters[5].rate = 16; break; case 0x6000: psxCounters[5].rate = 256; break; } // Need to set a rate and target if((psxCounters[5].mode & 0x7) == 0x7 || (psxCounters[5].mode & 0x7) == 0x1) { SysPrintf("Gate set on IOP C5, disabling\n"); psxCounters[5].mode |= IOPCNT_STOPPED; } psxCounters[5].count = 0; psxCounters[5].sCycleT = psxRegs.cycle; psxCounters[5].target &= 0xffffffff; _rcntSet( 5 ); }
static __forceinline void _rcntTestOverflow( int i ) { u64 maxTarget = ( i < 3 ) ? 0xffff : 0xfffffffful; if( psxCounters[i].count <= maxTarget ) return; PSXCNT_LOG("IOP Counter[%d] overflow 0x%I64x >= 0x%I64x (mode: %x)\n", i, psxCounters[i].count, maxTarget, psxCounters[i].mode ); if(psxCounters[i].mode & IOPCNT_INT_OVERFLOW) { // Overflow interrupt psxHu32(0x1070) |= psxCounters[i].interrupt; psxCounters[i].mode |= 0x1000; // Overflow flag if(psxCounters[i].mode & 0x80) psxCounters[i].mode &= ~0x0400; // Interrupt flag } // Update count and target. // Count wraps around back to zero, while the target is restored (if needed). // (high bit of the target gets set by rcntWtarget when the target is behind // the counter value, and thus should not be flagged until after an overflow) psxCounters[i].count &= maxTarget; psxCounters[i].target &= maxTarget; }
static void __fastcall _rcntTestTarget( int i ) { if( psxCounters[i].count < psxCounters[i].target ) return; PSXCNT_LOG("IOP Counter[%d] target 0x%I64x >= 0x%I64x (mode: %x)\n", i, psxCounters[i].count, psxCounters[i].target, psxCounters[i].mode); if (psxCounters[i].mode & IOPCNT_INT_TARGET) { // Target interrupt if(psxCounters[i].mode & 0x80) psxCounters[i].mode &= ~0x0400; // Interrupt flag psxCounters[i].mode |= 0x0800; // Target flag psxHu32(0x1070) |= psxCounters[i].interrupt; } if (psxCounters[i].mode & 0x08) { // Reset on target psxCounters[i].count -= psxCounters[i].target; if(!(psxCounters[i].mode & 0x40)) { SysPrintf("Counter %x repeat intr not set on zero ret, ignoring target\n", i); psxCounters[i].target |= IOPCNT_FUTURE_TARGET; } } else psxCounters[i].target |= IOPCNT_FUTURE_TARGET; }
void psxRcntWcount32(int index, u32 value) { u32 change; pxAssert( index >= 3 && index < 6 ); PSXCNT_LOG("32bit IOP Counter[%d] writeCount32 = %x", index, value); if(psxCounters[index].rate != PSXHBLANK) { // Re-adjust the sCycleT to match where the counter is currently // (remainder of the rate divided into the time passed will do the trick) change = psxRegs.cycle - psxCounters[index].sCycleT; psxCounters[index].sCycleT = psxRegs.cycle - (change % psxCounters[index].rate); } psxCounters[index].count = value; if ((psxCounters[index].mode & 0x400) || (psxCounters[index].mode & 0x40)) { //IRQ not triggered (one shot) or toggle psxCounters[index].target &= 0xffffffff; } if (value > psxCounters[index].target) {//Count already higher than Target //DevCon.Warning("32bit Count already higher than target"); psxCounters[index].target |= IOPCNT_FUTURE_TARGET; } _rcntSet( index ); }
u32 psxRcntRcount32(int index) { u32 retval = (u32)psxCounters[index].count; assert( index >= 3 && index < 6 ); PSXCNT_LOG("IOP Counter[%d] readCount32 = %lx\n", index, retval ); if( !( psxCounters[index].mode & IOPCNT_STOPPED ) && ( psxCounters[index].rate != PSXHBLANK ) ) { u32 delta = (u32)((psxRegs.cycle - psxCounters[index].sCycleT) / psxCounters[index].rate); retval += delta; PSXCNT_LOG(" (delta = %lx)\n", delta ); } return retval; }
u16 psxRcntRcount16(int index) { u32 retval = (u32)psxCounters[index].count; assert( index < 3 ); PSXCNT_LOG("IOP Counter[%d] readCount16 = %lx\n", index, (u16)retval ); // Don't count HBLANK timers // Don't count stopped gates either. if( !( psxCounters[index].mode & IOPCNT_STOPPED ) && ( psxCounters[index].rate != PSXHBLANK ) ) { u32 delta = (u32)((psxRegs.cycle - psxCounters[index].sCycleT) / psxCounters[index].rate); retval += delta; PSXCNT_LOG(" (delta = %lx)\n", delta ); } return (u16)retval; }
void psxRcnt3Wmode(u32 value) { PSXCNT_LOG("IOP Counter[3] writeMode = %lx\n", value); psxCounters[3].mode = value; psxCounters[3].rate = 1; psxCounters[3].mode|= 0x0400; if(value & IOPCNT_ALT_SOURCE) psxCounters[3].rate = PSXHBLANK; if(psxCounters[3].mode & IOPCNT_ENABLE_GATE) { PSXCNT_LOG("IOP Counter[3] Gate Check set, value = %x\n", value); psxvblankgate |= 1<<3; } else psxvblankgate &= ~(1<<3); psxCounters[3].count = 0; psxCounters[3].sCycleT = psxRegs.cycle; psxCounters[3].target &= 0xffffffff; _rcntSet( 3 ); }
void psxRcntWtarget16(int index, u32 value) { assert( index < 3 ); PSXCNT_LOG("IOP Counter[%d] writeTarget16 = %lx\n", index, value); psxCounters[index].target = value & 0xffff; // protect the target from an early arrival. // if the target is behind the current count, then set the target overflow // flag, so that the target won't be active until after the next overflow. if(psxCounters[index].target <= psxRcntCycles(index)) psxCounters[index].target |= IOPCNT_FUTURE_TARGET; _rcntSet( index ); }
void psxRcntWcount32(int index, u32 value) { u32 change; assert( index >= 3 && index < 6 ); PSXCNT_LOG("IOP Counter[%d] writeCount32 = %x\n", index, value); if(psxCounters[index].rate != PSXHBLANK) { // Re-adjust the sCycleT to match where the counter is currently // (remainder of the rate divided into the time passed will do the trick) change = psxRegs.cycle - psxCounters[index].sCycleT; psxCounters[index].sCycleT = psxRegs.cycle - (change % psxCounters[index].rate); } psxCounters[index].count = value & 0xffffffff; psxCounters[index].target &= 0xffffffff; _rcntSet( index ); }
static __fi void _rcntTestOverflow( int i ) { u64 maxTarget = ( i < 3 ) ? 0xffff : 0xfffffffful; if( psxCounters[i].count <= maxTarget ) return; PSXCNT_LOG("IOP Counter[%d] overflow 0x%I64x >= 0x%I64x (mode: %x)", i, psxCounters[i].count, maxTarget, psxCounters[i].mode ); if (!(psxCounters[i].mode & 0x40)) //One shot, whichever condition is met first { if (psxCounters[i].target < IOPCNT_FUTURE_TARGET) { //Target didn't trigger so we can overflow // Overflow interrupt if ((psxCounters[i].mode & IOPCNT_INT_OVERFLOW)) { if (_rcntFireInterrupt(i, true)) psxCounters[i].mode |= 0x1000; // Overflow flag } } psxCounters[i].target |= IOPCNT_FUTURE_TARGET; } else { // Overflow interrupt if ((psxCounters[i].mode & IOPCNT_INT_OVERFLOW)) { if (_rcntFireInterrupt(i, true)) psxCounters[i].mode |= 0x1000; // Overflow flag } psxCounters[i].target &= maxTarget; } // Update count. // Count wraps around back to zero, while the target is restored (if not in one shot mode). // (high bit of the target gets set by rcntWtarget when the target is behind // the counter value, and thus should not be flagged until after an overflow) psxCounters[i].count -= maxTarget; }
void psxRcnt2Wmode(u32 value) { PSXCNT_LOG("IOP Counter[0] writeMode = %lx\n", value); psxCounters[2].mode = value; psxCounters[2].mode|= 0x0400; switch(value & 0x200) { case 0x200: psxCounters[2].rate = 8; break; case 0x000: psxCounters[2].rate = 1; break; } if((psxCounters[2].mode & 0x7) == 0x7 || (psxCounters[2].mode & 0x7) == 0x1) { //SysPrintf("Gate set on IOP C2, disabling\n"); psxCounters[2].mode |= IOPCNT_STOPPED; } psxCounters[2].count = 0; psxCounters[2].sCycleT = psxRegs.cycle; psxCounters[2].target &= 0xffff; _rcntSet( 2 ); }
static void __fastcall _rcntTestTarget( int i ) { if( psxCounters[i].count < psxCounters[i].target ) return; PSXCNT_LOG("IOP Counter[%d] target 0x%I64x >= 0x%I64x (mode: %x)", i, psxCounters[i].count, psxCounters[i].target, psxCounters[i].mode); if (psxCounters[i].mode & IOPCNT_INT_TARGET) { // Target interrupt if(_rcntFireInterrupt(i, false)) psxCounters[i].mode |= 0x0800; // Target flag } if (psxCounters[i].mode & 0x08) { // Reset on target psxCounters[i].count -= psxCounters[i].target; } else psxCounters[i].target |= IOPCNT_FUTURE_TARGET; }
__fi void psxRcntWmode32( int index, u32 value ) { PSXCNT_LOG("32bit IOP Counter[%d] writeMode = 0x%04x", index, value ); int irqmode = 0; pxAssume( index >= 3 && index < 6 ); psxCounter& counter = psxCounters[index]; counter.mode = value; counter.mode |= 0x0400; //IRQ enable if (value & (1 << 4)) { irqmode += 1; } if (value & (1 << 5)) { irqmode += 2; } if (value & (1 << 7)) { PSXCNT_LOG("32 Counter %d Toggle IRQ on %s", index, (irqmode & 3) == 1 ? "Target" : ((irqmode & 3) == 2 ? "Overflow" : "Target and Overflow")); } else { PSXCNT_LOG("32 Counter %d Pulsed IRQ on %s", index, (irqmode & 3) == 1 ? "Target" : ((irqmode & 3) == 2 ? "Overflow" : "Target and Overflow")); } if (!(value & (1 << 6))) { PSXCNT_LOG("32 Counter %d One Shot", index); } else { PSXCNT_LOG("32 Counter %d Repeat", index); } if( index == 3 ) { // Counter 3 has the HBlank as an alternate source. counter.rate = 1; if(value & IOPCNT_ALT_SOURCE) counter.rate = PSXHBLANK; if(counter.mode & IOPCNT_ENABLE_GATE) { PSXCNT_LOG("IOP Counter[3] Gate Check set, value = %x", value); counter.mode |= IOPCNT_STOPPED; psxvblankgate |= 1<<3; } else psxvblankgate &= ~(1<<3); } else { switch(value & 0x6000) { case 0x0000: counter.rate = 1; break; case 0x2000: counter.rate = 8; break; case 0x4000: counter.rate = 16; break; case 0x6000: counter.rate = 256; break; } // Need to set a rate and target if((counter.mode & 0x7) == 0x7 || (counter.mode & 0x7) == 0x1) { Console.WriteLn( "Gate set on IOP Counter %d, disabling", index ); counter.mode |= IOPCNT_STOPPED; } } counter.count = 0; counter.sCycleT = psxRegs.cycle; counter.target &= 0xffffffff; _rcntSet( index ); }