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

Contents of /trunk/pcsx2/IopCounters.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 31 - (show annotations) (download)
Tue Sep 7 03:24:11 2010 UTC (9 years, 10 months ago) by william
File size: 20921 byte(s)
committing r3113 initial commit again...
1 /* 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 static __forceinline void _rcntTestOverflow( int i )
198 {
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 g_psxNextBranchCycle = psxRegs.cycle + 32;
395
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 __forceinline void psxRcntWmode16( int index, u32 value )
542 {
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 __forceinline void psxRcntWmode32( int index, u32 value )
603 {
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