/[pcsx2_0.9.7]/trunk/pcsx2/IopCounters.cpp
ViewVC logotype

Annotation of /trunk/pcsx2/IopCounters.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 62 - (hide annotations) (download)
Tue Sep 7 11:08:22 2010 UTC (9 years, 10 months ago) by william
File size: 20893 byte(s)
Auto Commited Import of: pcsx2-0.9.7-r3738-debug in ./trunk
1 william 31 /* PCSX2 - PS2 Emulator for PCs
2     * Copyright (C) 2002-2010 PCSX2 Dev Team
3     *
4     * PCSX2 is free software: you can redistribute it and/or modify it under the terms
5     * of the GNU Lesser General Public License as published by the Free Software Found-
6     * ation, either version 3 of the License, or (at your option) any later version.
7     *
8     * PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
9     * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
10     * PURPOSE. See the GNU General Public License for more details.
11     *
12     * You should have received a copy of the GNU General Public License along with PCSX2.
13     * If not, see <http://www.gnu.org/licenses/>.
14     */
15    
16    
17     // Note on INTC usage: All counters code is always called from inside the context of an
18     // event test, so instead of using the iopTestIntc we just set the 0x1070 flags directly.
19     // The EventText function will pick it up.
20    
21     #include "PrecompiledHeader.h"
22     #include "IopCommon.h"
23    
24     #include <math.h>
25    
26     /* Config.PsxType == 1: PAL:
27     VBlank interlaced 50.00 Hz
28     VBlank non-interlaced 49.76 Hz
29     HBlank 15.625 KHz
30     Config.PsxType == 0: NSTC
31     VBlank interlaced 59.94 Hz
32     VBlank non-interlaced 59.82 Hz
33     HBlank 15.73426573 KHz */
34    
35     // Misc IOP Clocks
36     #define PSXPIXEL ((int)(PSXCLK / 13500000))
37     #define PSXSOUNDCLK ((int)(48000))
38    
39     psxCounter psxCounters[NUM_COUNTERS];
40     s32 psxNextCounter;
41     u32 psxNextsCounter;
42     u8 psxhblankgate = 0;
43     u8 psxvblankgate = 0;
44    
45     // flags when the gate is off or counter disabled. (do not count)
46     #define IOPCNT_STOPPED (0x10000000ul)
47    
48     // used to disable targets until after an overflow
49     #define IOPCNT_FUTURE_TARGET (0x1000000000ULL)
50    
51     #define IOPCNT_ENABLE_GATE (1<<0) // enables gate-based counters
52     #define IOPCNT_INT_TARGET (1<<4) // 0x10 triggers an interrupt on targets
53     #define IOPCNT_INT_OVERFLOW (1<<5) // 0x20 triggers an interrupt on overflows
54     #define IOPCNT_ALT_SOURCE (1<<8) // 0x100 uses hblank on counters 1 and 3, and PSXCLOCK on counter 0
55    
56     // Use an arbitrary value to flag HBLANK counters.
57     // These counters will be counted by the hblank gates coming from the EE,
58     // which ensures they stay 100% in sync with the EE's hblank counters.
59     #define PSXHBLANK 0x2001
60    
61     static void psxRcntReset(int index)
62     {
63     psxCounters[index].count = 0;
64     psxCounters[index].mode&= ~0x18301C00;
65     psxCounters[index].sCycleT = psxRegs.cycle;
66     }
67    
68     static void _rcntSet( int cntidx )
69     {
70     u64 overflowCap = (cntidx>=3) ? 0x100000000ULL : 0x10000;
71     u64 c;
72    
73     const psxCounter& counter = psxCounters[cntidx];
74    
75     // psxNextCounter is relative to the psxRegs.cycle when rcntUpdate() was last called.
76     // However, the current _rcntSet could be called at any cycle count, so we need to take
77     // that into account. Adding the difference from that cycle count to the current one
78     // will do the trick!
79    
80     if( counter.mode & IOPCNT_STOPPED || counter.rate == PSXHBLANK) return;
81    
82     // check for special cases where the overflow or target has just passed
83     // (we probably missed it because we're doing/checking other things)
84     if( counter.count > overflowCap || counter.count > counter.target )
85     {
86     psxNextCounter = 4;
87     return;
88     }
89    
90     c = (u64)((overflowCap - counter.count) * counter.rate) - (psxRegs.cycle - counter.sCycleT);
91     c += psxRegs.cycle - psxNextsCounter; // adjust for time passed since last rcntUpdate();
92    
93     if(c < (u64)psxNextCounter)
94     {
95     psxNextCounter = (u32)c;
96     psxSetNextBranch( psxNextsCounter, psxNextCounter ); //Need to update on counter resets/target changes
97     }
98    
99     //if((counter.mode & 0x10) == 0 || psxCounters[i].target > 0xffff) continue;
100     if( counter.target & IOPCNT_FUTURE_TARGET ) return;
101    
102     c = (s64)((counter.target - counter.count) * counter.rate) - (psxRegs.cycle - counter.sCycleT);
103     c += psxRegs.cycle - psxNextsCounter; // adjust for time passed since last rcntUpdate();
104    
105     if(c < (u64)psxNextCounter)
106     {
107     psxNextCounter = (u32)c;
108     psxSetNextBranch( psxNextsCounter, psxNextCounter ); //Need to update on counter resets/target changes
109     }
110     }
111    
112    
113     void psxRcntInit() {
114     int i;
115    
116     memzero( psxCounters );
117    
118     for (i=0; i<3; i++) {
119     psxCounters[i].rate = 1;
120     psxCounters[i].mode|= 0x0400;
121     psxCounters[i].target = IOPCNT_FUTURE_TARGET;
122     }
123     for (i=3; i<6; i++) {
124     psxCounters[i].rate = 1;
125     psxCounters[i].mode|= 0x0400;
126     psxCounters[i].target = IOPCNT_FUTURE_TARGET;
127     }
128    
129     psxCounters[0].interrupt = 0x10;
130     psxCounters[1].interrupt = 0x20;
131     psxCounters[2].interrupt = 0x40;
132    
133     psxCounters[3].interrupt = 0x04000;
134     psxCounters[4].interrupt = 0x08000;
135     psxCounters[5].interrupt = 0x10000;
136    
137     if (SPU2async != NULL)
138     {
139     psxCounters[6].rate = 768*12;
140     psxCounters[6].CycleT = psxCounters[6].rate;
141     psxCounters[6].mode = 0x8;
142     }
143    
144     if (USBasync != NULL)
145     {
146     psxCounters[7].rate = PSXCLK/1000;
147     psxCounters[7].CycleT = psxCounters[7].rate;
148     psxCounters[7].mode = 0x8;
149     }
150    
151     #ifdef ENABLE_NEW_IOPDMA
152     psxCounters[8].rate = 2000;
153     psxCounters[8].CycleT = psxCounters[7].rate;
154     psxCounters[8].mode = 0x8;
155     #endif
156    
157     for (i=0; i<8; i++)
158     psxCounters[i].sCycleT = psxRegs.cycle;
159    
160     // Tell the IOP to branch ASAP, so that timers can get
161     // configured properly.
162     psxNextCounter = 1;
163     psxNextsCounter = psxRegs.cycle;
164     }
165    
166     static void __fastcall _rcntTestTarget( int i )
167     {
168     if( psxCounters[i].count < psxCounters[i].target ) return;
169    
170     PSXCNT_LOG("IOP Counter[%d] target 0x%I64x >= 0x%I64x (mode: %x)",
171     i, psxCounters[i].count, psxCounters[i].target, psxCounters[i].mode);
172    
173     if (psxCounters[i].mode & IOPCNT_INT_TARGET)
174     {
175     // Target interrupt
176    
177     if(psxCounters[i].mode & 0x80)
178     psxCounters[i].mode &= ~0x0400; // Interrupt flag
179     psxCounters[i].mode |= 0x0800; // Target flag
180    
181     psxHu32(0x1070) |= psxCounters[i].interrupt;
182     }
183    
184     if (psxCounters[i].mode & 0x08)
185     {
186     // Reset on target
187     psxCounters[i].count -= psxCounters[i].target;
188     if(!(psxCounters[i].mode & 0x40))
189     {
190     Console.WriteLn("Counter %x repeat intr not set on zero ret, ignoring target", i);
191     psxCounters[i].target |= IOPCNT_FUTURE_TARGET;
192     }
193     } else psxCounters[i].target |= IOPCNT_FUTURE_TARGET;
194     }
195    
196    
197 william 62 static __fi void _rcntTestOverflow( int i )
198 william 31 {
199     u64 maxTarget = ( i < 3 ) ? 0xffff : 0xfffffffful;
200     if( psxCounters[i].count <= maxTarget ) return;
201    
202     PSXCNT_LOG("IOP Counter[%d] overflow 0x%I64x >= 0x%I64x (mode: %x)",
203     i, psxCounters[i].count, maxTarget, psxCounters[i].mode );
204    
205     if(psxCounters[i].mode & IOPCNT_INT_OVERFLOW)
206     {
207     // Overflow interrupt
208     psxHu32(0x1070) |= psxCounters[i].interrupt;
209     psxCounters[i].mode |= 0x1000; // Overflow flag
210     if(psxCounters[i].mode & 0x80)
211     psxCounters[i].mode &= ~0x0400; // Interrupt flag
212     }
213    
214     // Update count and target.
215     // Count wraps around back to zero, while the target is restored (if needed).
216     // (high bit of the target gets set by rcntWtarget when the target is behind
217     // the counter value, and thus should not be flagged until after an overflow)
218    
219     psxCounters[i].count &= maxTarget;
220     psxCounters[i].target &= maxTarget;
221     }
222    
223     /*
224     Gate:
225     TM_NO_GATE 000
226     TM_GATE_ON_Count 001
227     TM_GATE_ON_ClearStart 011
228     TM_GATE_ON_Clear_OFF_Start 101
229     TM_GATE_ON_Start 111
230    
231     V-blank ----+ +----------------------------+ +------
232     | | | |
233     | | | |
234     +----+ +----+
235     TM_NO_GATE:
236    
237     0================================>============
238    
239     TM_GATE_ON_Count:
240    
241     <---->0==========================><---->0=====
242    
243     TM_GATE_ON_ClearStart:
244    
245     0====>0================================>0=====
246    
247     TM_GATE_ON_Clear_OFF_Start:
248    
249     0====><-------------------------->0====><-----
250    
251     TM_GATE_ON_Start:
252    
253     <---->0==========================>============
254     */
255    
256     static void _psxCheckStartGate( int i )
257     {
258     if(!(psxCounters[i].mode & IOPCNT_ENABLE_GATE)) return; //Ignore Gate
259    
260     switch((psxCounters[i].mode & 0x6) >> 1)
261     {
262     case 0x0: //GATE_ON_count - stop count on gate start:
263    
264     // get the current count at the time of stoppage:
265     psxCounters[i].count = ( i < 3 ) ?
266     psxRcntRcount16( i ) : psxRcntRcount32( i );
267     psxCounters[i].mode |= IOPCNT_STOPPED;
268     return;
269    
270     case 0x1: //GATE_ON_ClearStart - count normally with resets after every end gate
271     // do nothing - All counting will be done on a need-to-count basis.
272     return;
273    
274     case 0x2: //GATE_ON_Clear_OFF_Start - start counting on gate start, stop on gate end
275     psxCounters[i].count = 0;
276     psxCounters[i].sCycleT = psxRegs.cycle;
277     psxCounters[i].mode &= ~IOPCNT_STOPPED;
278     break;
279    
280     case 0x3: //GATE_ON_Start - start and count normally on gate end (no restarts or stops or clears)
281     // do nothing!
282     return;
283     }
284     _rcntSet( i );
285     }
286    
287     static void _psxCheckEndGate(int i)
288     {
289     if(!(psxCounters[i].mode & IOPCNT_ENABLE_GATE)) return; //Ignore Gate
290    
291     switch((psxCounters[i].mode & 0x6) >> 1)
292     {
293     case 0x0: //GATE_ON_count - reset and start counting
294     case 0x1: //GATE_ON_ClearStart - count normally with resets after every end gate
295     psxCounters[i].count = 0;
296     psxCounters[i].sCycleT = psxRegs.cycle;
297     psxCounters[i].mode &= ~IOPCNT_STOPPED;
298     break;
299    
300     case 0x2: //GATE_ON_Clear_OFF_Start - start counting on gate start, stop on gate end
301     psxCounters[i].count = ( i < 3 ) ?
302     psxRcntRcount16( i ) : psxRcntRcount32( i );
303     psxCounters[i].mode |= IOPCNT_STOPPED;
304     return; // do not set the counter
305    
306     case 0x3: //GATE_ON_Start - start and count normally (no restarts or stops or clears)
307     if( psxCounters[i].mode & IOPCNT_STOPPED )
308     {
309     psxCounters[i].count = 0;
310     psxCounters[i].sCycleT = psxRegs.cycle;
311     psxCounters[i].mode &= ~IOPCNT_STOPPED;
312     }
313     break;
314     }
315     _rcntSet( i );
316     }
317    
318     void psxCheckStartGate16(int i)
319     {
320     pxAssert( i < 3 );
321    
322     if(i == 0) // hSync counting...
323     {
324     // AlternateSource/scanline counters for Gates 1 and 3.
325     // We count them here so that they stay nicely synced with the EE's hsync.
326    
327     const u32 altSourceCheck = IOPCNT_ALT_SOURCE | IOPCNT_ENABLE_GATE;
328     const u32 stoppedGateCheck = (IOPCNT_STOPPED | altSourceCheck );
329    
330     // count if alt source is enabled and either:
331     // * the gate is enabled and not stopped.
332     // * the gate is disabled.
333    
334     if( (psxCounters[1].mode & altSourceCheck) == IOPCNT_ALT_SOURCE ||
335     (psxCounters[1].mode & stoppedGateCheck ) == altSourceCheck )
336     {
337     psxCounters[1].count++;
338     _rcntTestTarget( 1 );
339     _rcntTestOverflow( 1 );
340     }
341    
342     if( (psxCounters[3].mode & altSourceCheck) == IOPCNT_ALT_SOURCE ||
343     (psxCounters[3].mode & stoppedGateCheck ) == altSourceCheck )
344     {
345     psxCounters[3].count++;
346     _rcntTestTarget( 3 );
347     _rcntTestOverflow( 3 );
348     }
349     }
350    
351     _psxCheckStartGate( i );
352     }
353    
354     void psxCheckEndGate16(int i)
355     {
356     pxAssert(i < 3);
357     _psxCheckEndGate( i );
358     }
359    
360     static void psxCheckStartGate32(int i)
361     {
362     // 32 bit gate is called for gate 3 only. Ever.
363     pxAssert(i == 3);
364     _psxCheckStartGate( i );
365     }
366    
367     static void psxCheckEndGate32(int i)
368     {
369     pxAssert(i == 3);
370     _psxCheckEndGate( i );
371     }
372    
373    
374     void psxVBlankStart()
375     {
376     cdvdVsync();
377     psxHu32(0x1070) |= 1;
378     if(psxvblankgate & (1 << 1)) psxCheckStartGate16(1);
379     if(psxvblankgate & (1 << 3)) psxCheckStartGate32(3);
380     }
381    
382     void psxVBlankEnd()
383     {
384     psxHu32(0x1070) |= 0x800;
385     if(psxvblankgate & (1 << 1)) psxCheckEndGate16(1);
386     if(psxvblankgate & (1 << 3)) psxCheckEndGate32(3);
387     }
388    
389     void psxRcntUpdate()
390     {
391     int i;
392     //u32 change = 0;
393    
394 william 62 g_iopNextEventCycle = psxRegs.cycle + 32;
395 william 31
396     psxNextCounter = 0x7fffffff;
397     psxNextsCounter = psxRegs.cycle;
398    
399     for (i=0; i<=5; i++)
400     {
401     s32 change = psxRegs.cycle - psxCounters[i].sCycleT;
402    
403     // don't count disabled or hblank counters...
404     // We can't check the ALTSOURCE flag because the PSXCLOCK source *should*
405     // be counted here.
406    
407     if( psxCounters[i].mode & IOPCNT_STOPPED ) continue;
408     if( psxCounters[i].rate == PSXHBLANK ) continue;
409     if( change <= 0 ) continue;
410    
411     psxCounters[i].count += change / psxCounters[i].rate;
412     if(psxCounters[i].rate != 1)
413     {
414     change -= (change / psxCounters[i].rate) * psxCounters[i].rate;
415     psxCounters[i].sCycleT = psxRegs.cycle - change;
416     }
417     else
418     psxCounters[i].sCycleT = psxRegs.cycle;
419     }
420    
421     // Do target/overflow testing
422     // Optimization Note: This approach is very sound. Please do not try to unroll it
423     // as the size of the Test functions will cause code cache clutter and slowness.
424    
425     for( i=0; i<6; i++ )
426     {
427     // don't do target/oveflow checks for hblankers. Those
428     // checks are done when the counters are updated.
429     if( psxCounters[i].rate == PSXHBLANK ) continue;
430     if( psxCounters[i].mode & IOPCNT_STOPPED ) continue;
431    
432     _rcntTestTarget( i );
433     _rcntTestOverflow( i );
434    
435     // perform second target test because if we overflowed above it's possible we
436     // already shot past our target if it was very near zero.
437    
438     //if( psxCounters[i].count >= psxCounters[i].target ) _rcntTestTarget( i );
439     }
440    
441    
442     if(SPU2async)
443     {
444     const s32 difference = psxRegs.cycle - psxCounters[6].sCycleT;
445     s32 c = psxCounters[6].CycleT;
446    
447     if(difference >= psxCounters[6].CycleT)
448     {
449     SPU2async(difference);
450     psxCounters[6].sCycleT = psxRegs.cycle;
451     psxCounters[6].CycleT = psxCounters[6].rate;
452     }
453     else c -= difference;
454     psxNextCounter = c;
455     }
456    
457     if(USBasync)
458     {
459     const s32 difference = psxRegs.cycle - psxCounters[7].sCycleT;
460     s32 c = psxCounters[7].CycleT;
461    
462     if(difference >= psxCounters[7].CycleT)
463     {
464     USBasync(difference);
465     psxCounters[7].sCycleT = psxRegs.cycle;
466     psxCounters[7].CycleT = psxCounters[7].rate;
467     }
468     else c -= difference;
469     if (c < psxNextCounter) psxNextCounter = c;
470     }
471    
472     #ifdef ENABLE_NEW_IOPDMA
473    
474     // New Iop DMA handler WIP
475     {
476     const s32 difference = psxRegs.cycle - psxCounters[8].sCycleT;
477     s32 c = psxCounters[8].CycleT;
478    
479     if(difference >= psxCounters[8].CycleT)
480     {
481     psxCounters[8].sCycleT = psxRegs.cycle;
482     psxCounters[8].CycleT = psxCounters[8].rate;
483     IopDmaUpdate(difference);
484     }
485     else c -= difference;
486     if (c < psxNextCounter) psxNextCounter = c;
487     }
488     #endif
489    
490     for (i=0; i<6; i++) _rcntSet( i );
491     }
492    
493     //////////////////////////////////////////////////////////////////////////////////////////
494     //
495     void psxRcntWcount16(int index, u16 value)
496     {
497     u32 change;
498    
499     pxAssert( index < 3 );
500     PSXCNT_LOG("IOP Counter[%d] writeCount16 = %x", index, value);
501    
502     if(psxCounters[index].rate != PSXHBLANK)
503     {
504     // Re-adjust the sCycleT to match where the counter is currently
505     // (remainder of the rate divided into the time passed will do the trick)
506    
507     change = psxRegs.cycle - psxCounters[index].sCycleT;
508     psxCounters[index].sCycleT = psxRegs.cycle - (change % psxCounters[index].rate);
509     }
510    
511     psxCounters[index].count = value & 0xffff;
512     psxCounters[index].target &= 0xffff;
513     _rcntSet( index );
514     }
515    
516     //////////////////////////////////////////////////////////////////////////////////////////
517     //
518     void psxRcntWcount32(int index, u32 value)
519     {
520     u32 change;
521    
522     pxAssert( index >= 3 && index < 6 );
523     PSXCNT_LOG("IOP Counter[%d] writeCount32 = %x", index, value);
524    
525     if(psxCounters[index].rate != PSXHBLANK)
526     {
527     // Re-adjust the sCycleT to match where the counter is currently
528     // (remainder of the rate divided into the time passed will do the trick)
529    
530     change = psxRegs.cycle - psxCounters[index].sCycleT;
531     psxCounters[index].sCycleT = psxRegs.cycle - (change % psxCounters[index].rate);
532     }
533    
534     psxCounters[index].count = value & 0xffffffff;
535     psxCounters[index].target &= 0xffffffff;
536     _rcntSet( index );
537     }
538    
539     //////////////////////////////////////////////////////////////////////////////////////////
540     //
541 william 62 __fi void psxRcntWmode16( int index, u32 value )
542 william 31 {
543     PSXCNT_LOG( "IOP Counter[%d] writeMode = 0x%04X", index, value );
544    
545     jASSUME( index >= 0 && index < 3 );
546     psxCounter& counter = psxCounters[index];
547    
548     counter.mode = value;
549     counter.mode |= 0x0400;
550    
551     if( index == 2 )
552     {
553     switch(value & 0x200)
554     {
555     case 0x000: psxCounters[2].rate = 1; break;
556     case 0x200: psxCounters[2].rate = 8; break;
557     jNO_DEFAULT;
558     }
559    
560     if((counter.mode & 0x7) == 0x7 || (counter.mode & 0x7) == 0x1)
561     {
562     counter.mode |= IOPCNT_STOPPED;
563     }
564     }
565     else
566     {
567     // Counters 0 and 1 can select PIXEL or HSYNC as an alternate source:
568     counter.rate = 1;
569    
570     if(value & IOPCNT_ALT_SOURCE)
571     counter.rate = (index==0) ? PSXPIXEL : PSXHBLANK;
572    
573     if(counter.mode & IOPCNT_ENABLE_GATE)
574     {
575     // gated counters are added up as per the h/vblank timers.
576     // (the PIXEL alt source becomes a vsync gate)
577     counter.mode |= IOPCNT_STOPPED;
578     PSXCNT_LOG( "IOP Counter[%d] Gate Check set, value = 0x%04X", index, value );
579     if( index == 0 )
580     psxhblankgate |= 1; // fixme: these gate flags should be one var >_<
581     else
582     psxvblankgate |= 1<<1;
583     }
584     else
585     {
586     if( index == 0 )
587     psxhblankgate &= ~1;
588     else
589     psxvblankgate &= ~(1<<1);
590     }
591     }
592    
593     counter.count = 0;
594     counter.sCycleT = psxRegs.cycle;
595     counter.target &= 0xffff;
596    
597     _rcntSet( index );
598     }
599    
600     //////////////////////////////////////////////////////////////////////////////////////////
601     //
602 william 62 __fi void psxRcntWmode32( int index, u32 value )
603 william 31 {
604     PSXCNT_LOG( "IOP Counter[%d] writeMode = 0x%04x", index, value );
605    
606     jASSUME( index >= 3 && index < 6 );
607     psxCounter& counter = psxCounters[index];
608    
609     counter.mode = value;
610     counter.mode |= 0x0400;
611    
612     if( index == 3 )
613     {
614     // Counter 3 has the HBlank as an alternate source.
615     counter.rate = 1;
616     if(value & IOPCNT_ALT_SOURCE)
617     counter.rate = PSXHBLANK;
618    
619     if(counter.mode & IOPCNT_ENABLE_GATE)
620     {
621     PSXCNT_LOG("IOP Counter[3] Gate Check set, value = %x", value);
622     counter.mode |= IOPCNT_STOPPED;
623     psxvblankgate |= 1<<3;
624     }
625     else psxvblankgate &= ~(1<<3);
626     }
627     else
628     {
629     switch(value & 0x6000)
630     {
631     case 0x0000: counter.rate = 1; break;
632     case 0x2000: counter.rate = 8; break;
633     case 0x4000: counter.rate = 16; break;
634     case 0x6000: counter.rate = 256; break;
635     }
636    
637     // Need to set a rate and target
638     if((counter.mode & 0x7) == 0x7 || (counter.mode & 0x7) == 0x1)
639     {
640     Console.WriteLn( "Gate set on IOP Counter %d, disabling", index );
641     counter.mode |= IOPCNT_STOPPED;
642     }
643     }
644    
645     counter.count = 0;
646     counter.sCycleT = psxRegs.cycle;
647     counter.target &= 0xffffffff;
648     _rcntSet( index );
649     }
650    
651     //////////////////////////////////////////////////////////////////////////////////////////
652     //
653     void psxRcntWtarget16(int index, u32 value)
654     {
655     pxAssert( index < 3 );
656     PSXCNT_LOG("IOP Counter[%d] writeTarget16 = %lx", index, value);
657     psxCounters[index].target = value & 0xffff;
658    
659     // protect the target from an early arrival.
660     // if the target is behind the current count, then set the target overflow
661     // flag, so that the target won't be active until after the next overflow.
662    
663     if(psxCounters[index].target <= psxRcntCycles(index))
664     psxCounters[index].target |= IOPCNT_FUTURE_TARGET;
665    
666     _rcntSet( index );
667     }
668    
669     void psxRcntWtarget32(int index, u32 value)
670     {
671     pxAssert( index >= 3 && index < 6);
672     PSXCNT_LOG("IOP Counter[%d] writeTarget32 = %lx", index, value);
673    
674     psxCounters[index].target = value;
675    
676     // protect the target from an early arrival.
677     // if the target is behind the current count, then set the target overflow
678     // flag, so that the target won't be active until after the next overflow.
679    
680     if(psxCounters[index].target <= psxRcntCycles(index))
681     psxCounters[index].target |= IOPCNT_FUTURE_TARGET;
682    
683     _rcntSet( index );
684     }
685    
686     u16 psxRcntRcount16(int index)
687     {
688     u32 retval = (u32)psxCounters[index].count;
689    
690     pxAssert( index < 3 );
691    
692     PSXCNT_LOG("IOP Counter[%d] readCount16 = %lx", index, (u16)retval );
693    
694     // Don't count HBLANK timers
695     // Don't count stopped gates either.
696    
697     if( !( psxCounters[index].mode & IOPCNT_STOPPED ) &&
698     ( psxCounters[index].rate != PSXHBLANK ) )
699     {
700     u32 delta = (u32)((psxRegs.cycle - psxCounters[index].sCycleT) / psxCounters[index].rate);
701     retval += delta;
702     PSXCNT_LOG(" (delta = %lx)", delta );
703     }
704    
705     return (u16)retval;
706     }
707    
708     u32 psxRcntRcount32(int index)
709     {
710     u32 retval = (u32)psxCounters[index].count;
711    
712     pxAssert( index >= 3 && index < 6 );
713    
714     PSXCNT_LOG("IOP Counter[%d] readCount32 = %lx", index, retval );
715    
716     if( !( psxCounters[index].mode & IOPCNT_STOPPED ) &&
717     ( psxCounters[index].rate != PSXHBLANK ) )
718     {
719     u32 delta = (u32)((psxRegs.cycle - psxCounters[index].sCycleT) / psxCounters[index].rate);
720     retval += delta;
721     PSXCNT_LOG(" (delta = %lx)", delta );
722     }
723    
724     return retval;
725     }
726    
727     u64 psxRcntCycles(int index)
728     {
729     if(psxCounters[index].mode & IOPCNT_STOPPED || psxCounters[index].rate == PSXHBLANK ) return psxCounters[index].count;
730     return (u64)(psxCounters[index].count + (u32)((psxRegs.cycle - psxCounters[index].sCycleT) / psxCounters[index].rate));
731     }
732    
733     void psxRcntSetGates()
734     {
735     if(psxCounters[0].mode & IOPCNT_ENABLE_GATE)
736     psxhblankgate |= 1;
737     else
738     psxhblankgate &= ~1;
739    
740     if(psxCounters[1].mode & IOPCNT_ENABLE_GATE)
741     psxvblankgate |= 1<<1;
742     else
743     psxvblankgate &= ~(1<<1);
744    
745     if(psxCounters[3].mode & IOPCNT_ENABLE_GATE)
746     psxvblankgate |= 1<<3;
747     else
748     psxvblankgate &= ~(1<<3);
749     }
750    
751     void SaveStateBase::psxRcntFreeze()
752     {
753     FreezeTag( "iopCounters" );
754    
755     Freeze(psxCounters);
756     Freeze(psxNextCounter);
757     Freeze(psxNextsCounter);
758    
759     if( IsLoading() )
760     psxRcntSetGates();
761     }

  ViewVC Help
Powered by ViewVC 1.1.22