move some gpu status handling to core
[pcsx_rearmed.git] / libpcsxcore / psxcounters.c
1 /***************************************************************************
2  *   Copyright (C) 2010 by Blade_Arma                                      *
3  *                                                                         *
4  *   This program is free software; you can redistribute it and/or modify  *
5  *   it under the terms of the GNU General Public License as published by  *
6  *   the Free Software Foundation; either version 2 of the License, or     *
7  *   (at your option) any later version.                                   *
8  *                                                                         *
9  *   This program is distributed in the hope that it will be useful,       *
10  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
11  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
12  *   GNU General Public License for more details.                          *
13  *                                                                         *
14  *   You should have received a copy of the GNU General Public License     *
15  *   along with this program; if not, write to the                         *
16  *   Free Software Foundation, Inc.,                                       *
17  *   51 Franklin Street, Fifth Floor, Boston, MA 02111-1307 USA.           *
18  ***************************************************************************/
19
20 /*
21  * Internal PSX counters.
22  */
23
24 #include "psxcounters.h"
25 #include "gpu.h"
26 #include "debug.h"
27
28 /******************************************************************************/
29
30 enum
31 {
32     Rc0Gate           = 0x0001, // 0    not implemented
33     Rc1Gate           = 0x0001, // 0    not implemented
34     Rc2Disable        = 0x0001, // 0    partially implemented
35     RcUnknown1        = 0x0002, // 1    ?
36     RcUnknown2        = 0x0004, // 2    ?
37     RcCountToTarget   = 0x0008, // 3
38     RcIrqOnTarget     = 0x0010, // 4
39     RcIrqOnOverflow   = 0x0020, // 5
40     RcIrqRegenerate   = 0x0040, // 6
41     RcUnknown7        = 0x0080, // 7    ?
42     Rc0PixelClock     = 0x0100, // 8    fake implementation
43     Rc1HSyncClock     = 0x0100, // 8
44     Rc2Unknown8       = 0x0100, // 8    ?
45     Rc0Unknown9       = 0x0200, // 9    ?
46     Rc1Unknown9       = 0x0200, // 9    ?
47     Rc2OneEighthClock = 0x0200, // 9
48     RcUnknown10       = 0x0400, // 10   ?
49     RcCountEqTarget   = 0x0800, // 11
50     RcOverflow        = 0x1000, // 12
51     RcUnknown13       = 0x2000, // 13   ? (always zero)
52     RcUnknown14       = 0x4000, // 14   ? (always zero)
53     RcUnknown15       = 0x8000, // 15   ? (always zero)
54 };
55
56 #define CounterQuantity           ( 4 )
57 //static const u32 CounterQuantity  = 4;
58
59 static const u32 CountToOverflow  = 0;
60 static const u32 CountToTarget    = 1;
61
62 static const u32 FrameRate[]      = { 60, 50 };
63 static const u32 VBlankStart[]    = { 240, 256 };
64 static const u32 HSyncTotal[]     = { 263, 313 };
65 static const u32 SpuUpdInterval[] = { 32, 32 };
66
67 #define VERBOSE_LEVEL 0
68 static const s32 VerboseLevel     = VERBOSE_LEVEL;
69
70 /******************************************************************************/
71
72 Rcnt rcnts[ CounterQuantity ];
73
74 static u32 hSyncCount = 0;
75 static u32 spuSyncCount = 0;
76 static u32 hsync_steps = 0;
77 static u32 gpu_wants_hcnt = 0;
78 static u32 base_cycle = 0;
79 static u32 frame_counter = 0;
80
81 u32 psxNextCounter = 0, psxNextsCounter = 0;
82
83 /******************************************************************************/
84
85 static inline
86 void setIrq( u32 irq )
87 {
88     psxHu32ref(0x1070) |= SWAPu32(irq);
89 }
90
91 static
92 void verboseLog( u32 level, const char *str, ... )
93 {
94 #if VERBOSE_LEVEL > 0
95     if( level <= VerboseLevel )
96     {
97         va_list va;
98         char buf[ 4096 ];
99
100         va_start( va, str );
101         vsprintf( buf, str, va );
102         va_end( va );
103
104         printf( "%s", buf );
105         fflush( stdout );
106     }
107 #endif
108 }
109
110 /******************************************************************************/
111
112 static inline
113 void _psxRcntWcount( u32 index, u32 value )
114 {
115     if( value > 0xffff )
116     {
117         verboseLog( 1, "[RCNT %i] wcount > 0xffff: %x\n", index, value );
118         value &= 0xffff;
119     }
120
121     rcnts[index].cycleStart  = psxRegs.cycle;
122     rcnts[index].cycleStart -= value * rcnts[index].rate;
123
124     // TODO: <=.
125     if( value < rcnts[index].target )
126     {
127         rcnts[index].cycle = rcnts[index].target * rcnts[index].rate;
128         rcnts[index].counterState = CountToTarget;
129     }
130     else
131     {
132         rcnts[index].cycle = 0xffff * rcnts[index].rate;
133         rcnts[index].counterState = CountToOverflow;
134     }
135 }
136
137 static inline
138 u32 _psxRcntRcount( u32 index )
139 {
140     u32 count;
141
142     count  = psxRegs.cycle;
143     count -= rcnts[index].cycleStart;
144     if (rcnts[index].rate > 1)
145         count /= rcnts[index].rate;
146
147     if( count > 0xffff )
148     {
149         verboseLog( 1, "[RCNT %i] rcount > 0xffff: %x\n", index, count );
150         count &= 0xffff;
151     }
152
153     return count;
154 }
155
156 /******************************************************************************/
157
158 static
159 void psxRcntSet()
160 {
161     s32 countToUpdate;
162     u32 i;
163
164     psxNextsCounter = psxRegs.cycle;
165     psxNextCounter  = 0x7fffffff;
166
167     for( i = 0; i < CounterQuantity; ++i )
168     {
169         countToUpdate = rcnts[i].cycle - (psxNextsCounter - rcnts[i].cycleStart);
170
171         if( countToUpdate < 0 )
172         {
173             psxNextCounter = 0;
174             break;
175         }
176
177         if( countToUpdate < (s32)psxNextCounter )
178         {
179             psxNextCounter = countToUpdate;
180         }
181     }
182
183     psxRegs.interrupt |= (1 << PSXINT_RCNT);
184     new_dyna_set_event(PSXINT_RCNT, psxNextCounter);
185 }
186
187 /******************************************************************************/
188
189 static
190 void psxRcntReset( u32 index )
191 {
192     u32 count;
193
194     if( rcnts[index].counterState == CountToTarget )
195     {
196         if( rcnts[index].mode & RcCountToTarget )
197         {
198             count  = psxRegs.cycle;
199             count -= rcnts[index].cycleStart;
200             if (rcnts[index].rate > 1)
201                 count /= rcnts[index].rate;
202             count -= rcnts[index].target;
203         }
204         else
205         {
206             count = _psxRcntRcount( index );
207         }
208
209         _psxRcntWcount( index, count );
210
211         if( rcnts[index].mode & RcIrqOnTarget )
212         {
213             if( (rcnts[index].mode & RcIrqRegenerate) || (!rcnts[index].irqState) )
214             {
215                 verboseLog( 3, "[RCNT %i] irq: %x\n", index, count );
216                 setIrq( rcnts[index].irq );
217                 rcnts[index].irqState = 1;
218             }
219         }
220
221         rcnts[index].mode |= RcCountEqTarget;
222     }
223     else if( rcnts[index].counterState == CountToOverflow )
224     {
225         count  = psxRegs.cycle;
226         count -= rcnts[index].cycleStart;
227         if (rcnts[index].rate > 1)
228             count /= rcnts[index].rate;
229         count -= 0xffff;
230
231         _psxRcntWcount( index, count );
232
233         if( rcnts[index].mode & RcIrqOnOverflow )
234         {
235             if( (rcnts[index].mode & RcIrqRegenerate) || (!rcnts[index].irqState) )
236             {
237                 verboseLog( 3, "[RCNT %i] irq: %x\n", index, count );
238                 setIrq( rcnts[index].irq );
239                 rcnts[index].irqState = 1;
240             }
241         }
242
243         rcnts[index].mode |= RcOverflow;
244     }
245
246     rcnts[index].mode |= RcUnknown10;
247
248     psxRcntSet();
249 }
250
251 void psxRcntUpdate()
252 {
253     u32 cycle;
254
255     cycle = psxRegs.cycle;
256
257     // rcnt 0.
258     if( cycle - rcnts[0].cycleStart >= rcnts[0].cycle )
259     {
260         psxRcntReset( 0 );
261     }
262
263     // rcnt 1.
264     if( cycle - rcnts[1].cycleStart >= rcnts[1].cycle )
265     {
266         psxRcntReset( 1 );
267     }
268
269     // rcnt 2.
270     if( cycle - rcnts[2].cycleStart >= rcnts[2].cycle )
271     {
272         psxRcntReset( 2 );
273     }
274
275     // rcnt base.
276     if( cycle - rcnts[3].cycleStart >= rcnts[3].cycle )
277     {
278         u32 leftover_cycles = cycle - rcnts[3].cycleStart - rcnts[3].cycle;
279         u32 next_vsync, next_lace;
280
281         spuSyncCount += hsync_steps;
282         hSyncCount += hsync_steps;
283
284         // Update spu.
285         if( spuSyncCount >= SpuUpdInterval[Config.PsxType] )
286         {
287             spuSyncCount = 0;
288
289             if( SPU_async )
290             {
291                 SPU_async( SpuUpdInterval[Config.PsxType] * rcnts[3].target );
292             }
293         }
294         
295         // VSync irq.
296         if( hSyncCount == VBlankStart[Config.PsxType] )
297         {
298             GPU_vBlank( 1, &hSyncCount, &gpu_wants_hcnt );
299             //if( !(HW_GPU_STATUS & PSXGPU_ILACE) ) // hmh
300                 HW_GPU_STATUS |= PSXGPU_LCF;
301
302             // For the best times. :D
303             //setIrq( 0x01 );
304         }
305         
306         // Update lace. (with InuYasha fix)
307         if( hSyncCount >= (Config.VSyncWA ? HSyncTotal[Config.PsxType] / BIAS : HSyncTotal[Config.PsxType]) )
308         {
309             hSyncCount = 0;
310             frame_counter++;
311
312             GPU_vBlank( 0, &hSyncCount, &gpu_wants_hcnt );
313             setIrq( 0x01 );
314
315             EmuUpdate();
316             GPU_updateLace();
317
318             HW_GPU_STATUS &= ~PSXGPU_LCF;
319             if( HW_GPU_STATUS & PSXGPU_ILACE )
320                 HW_GPU_STATUS |= frame_counter << 31;
321         }
322
323         // Schedule next call, in hsyncs
324         hsync_steps = SpuUpdInterval[Config.PsxType] - spuSyncCount;
325         next_vsync = VBlankStart[Config.PsxType] - hSyncCount; // ok to overflow
326         next_lace = HSyncTotal[Config.PsxType] - hSyncCount;
327         if( next_vsync && next_vsync < hsync_steps )
328             hsync_steps = next_vsync;
329         if( next_lace && next_lace < hsync_steps )
330             hsync_steps = next_lace;
331         if( gpu_wants_hcnt )
332             hsync_steps = 1;
333
334         rcnts[3].cycleStart = cycle - leftover_cycles;
335         if (Config.PsxType)
336                 // 20.12 precision, clk / 50 / 313 ~= 2164.14
337                 base_cycle += hsync_steps * 8864320;
338         else
339                 // clk / 60 / 263 ~= 2146.31
340                 base_cycle += hsync_steps * 8791293;
341         rcnts[3].cycle = base_cycle >> 12;
342         base_cycle &= 0xfff;
343         psxRcntSet();
344     }
345
346 #ifndef NDEBUG
347     DebugVSync();
348 #endif
349 }
350
351 /******************************************************************************/
352
353 void psxRcntWcount( u32 index, u32 value )
354 {
355     verboseLog( 2, "[RCNT %i] wcount: %x\n", index, value );
356
357     _psxRcntWcount( index, value );
358     psxRcntSet();
359 }
360
361 void psxRcntWmode( u32 index, u32 value )
362 {
363     verboseLog( 1, "[RCNT %i] wmode: %x\n", index, value );
364
365     rcnts[index].mode = value;
366     rcnts[index].irqState = 0;
367
368     switch( index )
369     {
370         case 0:
371             if( value & Rc0PixelClock )
372             {
373                 rcnts[index].rate = 5;
374             }
375             else
376             {
377                 rcnts[index].rate = 1;
378             }
379         break;
380         case 1:
381             if( value & Rc1HSyncClock )
382             {
383                 rcnts[index].rate = (PSXCLK / (FrameRate[Config.PsxType] * HSyncTotal[Config.PsxType]));
384             }
385             else
386             {
387                 rcnts[index].rate = 1;
388             }
389         break;
390         case 2:
391             if( value & Rc2OneEighthClock )
392             {
393                 rcnts[index].rate = 8;
394             }
395             else
396             {
397                 rcnts[index].rate = 1;
398             }
399
400             // TODO: wcount must work.
401             if( value & Rc2Disable )
402             {
403                 rcnts[index].rate = 0xffffffff;
404             }
405         break;
406     }
407
408     _psxRcntWcount( index, 0 );
409     psxRcntSet();
410 }
411
412 void psxRcntWtarget( u32 index, u32 value )
413 {
414     verboseLog( 1, "[RCNT %i] wtarget: %x\n", index, value );
415
416     rcnts[index].target = value;
417
418     _psxRcntWcount( index, _psxRcntRcount( index ) );
419     psxRcntSet();
420 }
421
422 /******************************************************************************/
423
424 u32 psxRcntRcount( u32 index )
425 {
426     u32 count;
427
428     count = _psxRcntRcount( index );
429
430     // Parasite Eve 2 fix.
431     if( Config.RCntFix )
432     {
433         if( index == 2 )
434         {
435             if( rcnts[index].counterState == CountToTarget )
436             {
437                 count /= BIAS;
438             }
439         }
440     }
441
442     verboseLog( 2, "[RCNT %i] rcount: %x\n", index, count );
443
444     return count;
445 }
446
447 u32 psxRcntRmode( u32 index )
448 {
449     u16 mode;
450
451     mode = rcnts[index].mode;
452     rcnts[index].mode &= 0xe7ff;
453
454     verboseLog( 2, "[RCNT %i] rmode: %x\n", index, mode );
455
456     return mode;
457 }
458
459 u32 psxRcntRtarget( u32 index )
460 {
461     verboseLog( 2, "[RCNT %i] rtarget: %x\n", index, rcnts[index].target );
462
463     return rcnts[index].target;
464 }
465
466 /******************************************************************************/
467
468 void psxRcntInit()
469 {
470     s32 i;
471
472     // rcnt 0.
473     rcnts[0].rate   = 1;
474     rcnts[0].irq    = 0x10;
475
476     // rcnt 1.
477     rcnts[1].rate   = 1;
478     rcnts[1].irq    = 0x20;
479
480     // rcnt 2.
481     rcnts[2].rate   = 1;
482     rcnts[2].irq    = 0x40;
483
484     // rcnt base.
485     rcnts[3].rate   = 1;
486     rcnts[3].mode   = RcCountToTarget;
487     rcnts[3].target = (PSXCLK / (FrameRate[Config.PsxType] * HSyncTotal[Config.PsxType]));
488
489     for( i = 0; i < CounterQuantity; ++i )
490     {
491         _psxRcntWcount( i, 0 );
492     }
493
494     hSyncCount = 0;
495     spuSyncCount = 0;
496     hsync_steps = 1;
497
498     psxRcntSet();
499 }
500
501 /******************************************************************************/
502
503 s32 psxRcntFreeze( gzFile f, s32 Mode )
504 {
505     gzfreeze( &rcnts, sizeof(rcnts) );
506     gzfreeze( &hSyncCount, sizeof(hSyncCount) );
507     gzfreeze( &spuSyncCount, sizeof(spuSyncCount) );
508     gzfreeze( &psxNextCounter, sizeof(psxNextCounter) );
509     gzfreeze( &psxNextsCounter, sizeof(psxNextsCounter) );
510
511     if (Mode == 0)
512         hsync_steps = (psxRegs.cycle - rcnts[3].cycleStart) / rcnts[3].target;
513
514     base_cycle = 0;
515
516     return 0;
517 }
518
519 /******************************************************************************/