frontend: update libpicofe, fix missed callbacks
[pcsx_rearmed.git] / libpcsxcore / psxcounters.c
... / ...
CommitLineData
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 "psxevents.h"
26#include "gpu.h"
27//#include "debug.h"
28#define DebugVSync()
29
30/******************************************************************************/
31
32enum
33{
34 RcSyncModeEnable = 0x0001, // 0
35 Rc01BlankPause = 0 << 1, // 1,2
36 Rc01UnblankReset = 1 << 1, // 1,2
37 Rc01UnblankReset2 = 2 << 1, // 1,2
38 Rc2Stop = 0 << 1, // 1,2
39 Rc2Stop2 = 3 << 1, // 1,2
40 RcCountToTarget = 0x0008, // 3
41 RcIrqOnTarget = 0x0010, // 4
42 RcIrqOnOverflow = 0x0020, // 5
43 RcIrqRegenerate = 0x0040, // 6
44 RcUnknown7 = 0x0080, // 7 ?
45 Rc0PixelClock = 0x0100, // 8 fake implementation
46 Rc1HSyncClock = 0x0100, // 8
47 Rc2Unknown8 = 0x0100, // 8 ?
48 Rc0Unknown9 = 0x0200, // 9 ?
49 Rc1Unknown9 = 0x0200, // 9 ?
50 Rc2OneEighthClock = 0x0200, // 9
51 RcUnknown10 = 0x0400, // 10 ?
52 RcCountEqTarget = 0x0800, // 11
53 RcOverflow = 0x1000, // 12
54 RcUnknown13 = 0x2000, // 13 ? (always zero)
55 RcUnknown14 = 0x4000, // 14 ? (always zero)
56 RcUnknown15 = 0x8000, // 15 ? (always zero)
57};
58
59#define CounterQuantity ( 4 )
60//static const u32 CounterQuantity = 4;
61
62static const u32 CountToOverflow = 0;
63static const u32 CountToTarget = 1;
64
65static const u32 HSyncTotal[] = { 263, 314 };
66#define VBlankStart 240 // todo: depend on the actual GPU setting
67
68#define VERBOSE_LEVEL 0
69
70/******************************************************************************/
71#ifdef DRC_DISABLE
72Rcnt rcnts[ CounterQuantity ];
73#endif
74unsigned int hSyncCount = 0;
75unsigned int frame_counter = 0;
76static u32 hsync_steps = 0;
77
78/******************************************************************************/
79
80#define FPS_FRACTIONAL_PAL (53203425/314./3406) // ~49.75
81#define FPS_FRACTIONAL_NTSC (53693175/263./3413) // ~59.81
82
83static inline
84u32 frameCycles(void)
85{
86 int ff = Config.FractionalFramerate >= 0
87 ? Config.FractionalFramerate : Config.hacks.fractional_Framerate;
88 if (ff)
89 {
90 if (Config.PsxType)
91 return (u32)(PSXCLK / FPS_FRACTIONAL_PAL);
92 else
93 return (u32)(PSXCLK / FPS_FRACTIONAL_NTSC);
94 }
95 return Config.PsxType ? (PSXCLK / 50) : (PSXCLK / 60);
96}
97
98// used to inform the frontend about the exact framerate
99double psxGetFps()
100{
101 int ff = Config.FractionalFramerate >= 0
102 ? Config.FractionalFramerate : Config.hacks.fractional_Framerate;
103 if (ff)
104 return Config.PsxType ? FPS_FRACTIONAL_PAL : FPS_FRACTIONAL_NTSC;
105 else
106 return Config.PsxType ? 50.0 : 60.0;
107}
108
109// to inform the frontend about the exact famerate
110static inline
111u32 lineCycles(void)
112{
113 // should be more like above, but our timing is already poor anyway
114 if (Config.PsxType)
115 return PSXCLK / 50 / HSyncTotal[1];
116 else
117 return PSXCLK / 60 / HSyncTotal[0];
118}
119
120static inline
121void setIrq( u32 irq )
122{
123 psxHu32ref(0x1070) |= SWAPu32(irq);
124}
125
126static
127void verboseLog( u32 level, const char *str, ... )
128{
129#if VERBOSE_LEVEL > 0
130 if( level <= VERBOSE_LEVEL )
131 {
132 va_list va;
133 char buf[ 4096 ];
134
135 va_start( va, str );
136 vsprintf( buf, str, va );
137 va_end( va );
138
139 printf( "%s", buf );
140 fflush( stdout );
141 }
142#endif
143}
144
145/******************************************************************************/
146
147static inline
148void _psxRcntWcount( u32 index, u32 value )
149{
150 value &= 0xffff;
151
152 rcnts[index].cycleStart = psxRegs.cycle;
153 rcnts[index].cycleStart -= value * rcnts[index].rate;
154
155 // TODO: <=.
156 if( value < rcnts[index].target )
157 {
158 rcnts[index].cycle = rcnts[index].target * rcnts[index].rate;
159 rcnts[index].counterState = CountToTarget;
160 }
161 else
162 {
163 rcnts[index].cycle = 0x10000 * rcnts[index].rate;
164 rcnts[index].counterState = CountToOverflow;
165 }
166}
167
168static inline
169u32 _psxRcntRcount( u32 index )
170{
171 u32 count;
172
173 count = psxRegs.cycle;
174 count -= rcnts[index].cycleStart;
175 if (rcnts[index].rate > 1)
176 count /= rcnts[index].rate;
177
178 if( count > 0x10000 )
179 {
180 verboseLog( 1, "[RCNT %i] rcount > 0x10000: %x\n", index, count );
181 }
182 count &= 0xffff;
183
184 return count;
185}
186
187static
188void _psxRcntWmode( u32 index, u32 value )
189{
190 rcnts[index].mode = value;
191
192 switch( index )
193 {
194 case 0:
195 if( value & Rc0PixelClock )
196 {
197 rcnts[index].rate = 5;
198 }
199 else
200 {
201 rcnts[index].rate = 1;
202 }
203 break;
204 case 1:
205 if( value & Rc1HSyncClock )
206 {
207 rcnts[index].rate = lineCycles();
208 }
209 else
210 {
211 rcnts[index].rate = 1;
212 }
213 break;
214 case 2:
215 if( value & Rc2OneEighthClock )
216 {
217 rcnts[index].rate = 8;
218 }
219 else
220 {
221 rcnts[index].rate = 1;
222 }
223
224 // TODO: wcount must work.
225 if( (value & 7) == (RcSyncModeEnable | Rc2Stop) ||
226 (value & 7) == (RcSyncModeEnable | Rc2Stop2) )
227 {
228 rcnts[index].rate = 0xffffffff;
229 }
230 break;
231 }
232}
233
234/******************************************************************************/
235
236static
237void psxRcntSet()
238{
239 s32 countToUpdate;
240 u32 i;
241
242 psxRegs.psxNextsCounter = psxRegs.cycle;
243 psxRegs.psxNextCounter = 0x7fffffff;
244
245 for( i = 0; i < CounterQuantity; ++i )
246 {
247 countToUpdate = rcnts[i].cycle - (psxRegs.psxNextsCounter - rcnts[i].cycleStart);
248
249 if( countToUpdate < 0 )
250 {
251 psxRegs.psxNextCounter = 0;
252 break;
253 }
254
255 if( countToUpdate < (s32)psxRegs.psxNextCounter )
256 {
257 psxRegs.psxNextCounter = countToUpdate;
258 }
259 }
260
261 set_event(PSXINT_RCNT, psxRegs.psxNextCounter);
262}
263
264/******************************************************************************/
265
266static
267void psxRcntReset( u32 index )
268{
269 u32 rcycles;
270
271 rcnts[index].mode |= RcUnknown10;
272
273 if( rcnts[index].counterState == CountToTarget )
274 {
275 rcycles = psxRegs.cycle - rcnts[index].cycleStart;
276 if( rcnts[index].mode & RcCountToTarget )
277 {
278 rcycles -= rcnts[index].target * rcnts[index].rate;
279 rcnts[index].cycleStart = psxRegs.cycle - rcycles;
280 }
281 else
282 {
283 rcnts[index].cycle = 0x10000 * rcnts[index].rate;
284 rcnts[index].counterState = CountToOverflow;
285 }
286
287 if( rcnts[index].mode & RcIrqOnTarget )
288 {
289 if( (rcnts[index].mode & RcIrqRegenerate) || (!rcnts[index].irqState) )
290 {
291 verboseLog( 3, "[RCNT %i] irq\n", index );
292 setIrq( rcnts[index].irq );
293 rcnts[index].irqState = 1;
294 }
295 }
296
297 rcnts[index].mode |= RcCountEqTarget;
298
299 if( rcycles < 0x10000 * rcnts[index].rate )
300 return;
301 }
302
303 if( rcnts[index].counterState == CountToOverflow )
304 {
305 rcycles = psxRegs.cycle - rcnts[index].cycleStart;
306 rcycles -= 0x10000 * rcnts[index].rate;
307
308 rcnts[index].cycleStart = psxRegs.cycle - rcycles;
309
310 if( rcycles < rcnts[index].target * rcnts[index].rate )
311 {
312 rcnts[index].cycle = rcnts[index].target * rcnts[index].rate;
313 rcnts[index].counterState = CountToTarget;
314 }
315
316 if( rcnts[index].mode & RcIrqOnOverflow )
317 {
318 if( (rcnts[index].mode & RcIrqRegenerate) || (!rcnts[index].irqState) )
319 {
320 verboseLog( 3, "[RCNT %i] irq\n", index );
321 setIrq( rcnts[index].irq );
322 rcnts[index].irqState = 1;
323 }
324 }
325
326 rcnts[index].mode |= RcOverflow;
327 }
328}
329
330static void scheduleRcntBase(void)
331{
332 // Schedule next call, in hsyncs
333 if (hSyncCount < VBlankStart)
334 hsync_steps = VBlankStart - hSyncCount;
335 else
336 hsync_steps = HSyncTotal[Config.PsxType] - hSyncCount;
337
338 if (hSyncCount + hsync_steps == HSyncTotal[Config.PsxType])
339 {
340 rcnts[3].cycle = frameCycles();
341 }
342 else
343 {
344 // clk / 50 / 314 ~= 2157.25
345 // clk / 60 / 263 ~= 2146.31
346 u32 mult = Config.PsxType ? 8836089 : 8791293;
347 rcnts[3].cycle = hsync_steps * mult >> 12;
348 }
349}
350
351void psxRcntUpdate()
352{
353 u32 cycle, cycles_passed;
354
355 cycle = psxRegs.cycle;
356
357 // rcnt 0.
358 cycles_passed = cycle - rcnts[0].cycleStart;
359 while( cycles_passed >= rcnts[0].cycle )
360 {
361 if (((rcnts[0].mode & 7) == (RcSyncModeEnable | Rc01UnblankReset) ||
362 (rcnts[0].mode & 7) == (RcSyncModeEnable | Rc01UnblankReset2))
363 && cycles_passed > lineCycles())
364 {
365 u32 q = cycles_passed / (lineCycles() + 1u);
366 rcnts[0].cycleStart += q * lineCycles();
367 break;
368 }
369 else
370 psxRcntReset( 0 );
371
372 cycles_passed = cycle - rcnts[0].cycleStart;
373 }
374
375 // rcnt 1.
376 while( cycle - rcnts[1].cycleStart >= rcnts[1].cycle )
377 {
378 psxRcntReset( 1 );
379 }
380
381 // rcnt 2.
382 while( cycle - rcnts[2].cycleStart >= rcnts[2].cycle )
383 {
384 psxRcntReset( 2 );
385 }
386
387 // rcnt base.
388 if( cycle - rcnts[3].cycleStart >= rcnts[3].cycle )
389 {
390 hSyncCount += hsync_steps;
391
392 // VSync irq.
393 if( hSyncCount == VBlankStart )
394 {
395 HW_GPU_STATUS &= SWAP32(~PSXGPU_LCF);
396 GPU_vBlank( 1, 0 );
397 setIrq( 0x01 );
398
399 EmuUpdate();
400 GPU_updateLace();
401
402 if( SPU_async )
403 {
404 SPU_async( cycle, 1 );
405 }
406 }
407
408 // Update lace.
409 if( hSyncCount >= HSyncTotal[Config.PsxType] )
410 {
411 u32 status, field = 0;
412 rcnts[3].cycleStart += frameCycles();
413 hSyncCount = 0;
414 frame_counter++;
415
416 gpuSyncPluginSR();
417 status = SWAP32(HW_GPU_STATUS) | PSXGPU_FIELD;
418 if ((status & PSXGPU_ILACE_BITS) == PSXGPU_ILACE_BITS) {
419 field = frame_counter & 1;
420 status |= field << 31;
421 status ^= field << 13;
422 }
423 HW_GPU_STATUS = SWAP32(status);
424 GPU_vBlank(0, field);
425 if ((s32)(psxRegs.gpuIdleAfter - psxRegs.cycle) < 0)
426 psxRegs.gpuIdleAfter = psxRegs.cycle - 1; // prevent overflow
427
428 if ((rcnts[0].mode & 7) == (RcSyncModeEnable | Rc01UnblankReset) ||
429 (rcnts[0].mode & 7) == (RcSyncModeEnable | Rc01UnblankReset2))
430 {
431 rcnts[0].cycleStart = rcnts[3].cycleStart;
432 }
433
434 if ((rcnts[1].mode & 7) == (RcSyncModeEnable | Rc01UnblankReset) ||
435 (rcnts[1].mode & 7) == (RcSyncModeEnable | Rc01UnblankReset2))
436 {
437 rcnts[1].cycleStart = rcnts[3].cycleStart;
438 }
439 else if (rcnts[1].mode & Rc1HSyncClock)
440 {
441 // adjust to remove the rounding error
442 _psxRcntWcount(1, (psxRegs.cycle - rcnts[1].cycleStart) / rcnts[1].rate);
443 }
444 }
445
446 scheduleRcntBase();
447 }
448
449 psxRcntSet();
450
451#if 0 //ndef NDEBUG
452 DebugVSync();
453#endif
454}
455
456/******************************************************************************/
457
458void psxRcntWcount( u32 index, u32 value )
459{
460 verboseLog( 2, "[RCNT %i] wcount: %x\n", index, value );
461
462 _psxRcntWcount( index, value );
463 psxRcntSet();
464}
465
466void psxRcntWmode( u32 index, u32 value )
467{
468 verboseLog( 1, "[RCNT %i] wmode: %x\n", index, value );
469
470 _psxRcntWmode( index, value );
471 _psxRcntWcount( index, 0 );
472
473 rcnts[index].irqState = 0;
474 psxRcntSet();
475}
476
477void psxRcntWtarget( u32 index, u32 value )
478{
479 verboseLog( 1, "[RCNT %i] wtarget: %x\n", index, value );
480
481 rcnts[index].target = value;
482
483 _psxRcntWcount( index, _psxRcntRcount( index ) );
484 psxRcntSet();
485}
486
487/******************************************************************************/
488
489u32 psxRcntRcount0()
490{
491 u32 index = 0;
492 u32 count;
493
494 if ((rcnts[0].mode & 7) == (RcSyncModeEnable | Rc01UnblankReset) ||
495 (rcnts[0].mode & 7) == (RcSyncModeEnable | Rc01UnblankReset2))
496 {
497 count = psxRegs.cycle - rcnts[index].cycleStart;
498 //count = ((16u * count) % (16u * PSXCLK / 60 / 263)) / 16u;
499 count = count % lineCycles();
500 rcnts[index].cycleStart = psxRegs.cycle - count;
501 }
502 else
503 count = _psxRcntRcount( index );
504
505 verboseLog( 2, "[RCNT 0] rcount: %04x m: %04x\n", count, rcnts[index].mode);
506
507 return count;
508}
509
510u32 psxRcntRcount1()
511{
512 u32 index = 1;
513 u32 count;
514
515 count = _psxRcntRcount( index );
516
517 verboseLog( 2, "[RCNT 1] rcount: %04x m: %04x\n", count, rcnts[index].mode);
518
519 return count;
520}
521
522u32 psxRcntRcount2()
523{
524 u32 index = 2;
525 u32 count;
526
527 count = _psxRcntRcount( index );
528
529 verboseLog( 2, "[RCNT 2] rcount: %04x m: %04x\n", count, rcnts[index].mode);
530
531 return count;
532}
533
534u32 psxRcntRmode( u32 index )
535{
536 u16 mode;
537
538 mode = rcnts[index].mode;
539 rcnts[index].mode &= 0xe7ff;
540
541 verboseLog( 2, "[RCNT %i] rmode: %x\n", index, mode );
542
543 return mode;
544}
545
546u32 psxRcntRtarget( u32 index )
547{
548 verboseLog( 2, "[RCNT %i] rtarget: %x\n", index, rcnts[index].target );
549
550 return rcnts[index].target;
551}
552
553/******************************************************************************/
554
555void psxRcntInit()
556{
557 s32 i;
558
559 // rcnt 0.
560 rcnts[0].rate = 1;
561 rcnts[0].irq = 0x10;
562
563 // rcnt 1.
564 rcnts[1].rate = 1;
565 rcnts[1].irq = 0x20;
566
567 // rcnt 2.
568 rcnts[2].rate = 1;
569 rcnts[2].irq = 0x40;
570
571 // rcnt base.
572 rcnts[3].rate = 1;
573
574 for( i = 0; i < CounterQuantity; ++i )
575 {
576 _psxRcntWcount( i, 0 );
577 }
578
579 hSyncCount = 0;
580 hsync_steps = 1;
581
582 scheduleRcntBase();
583 psxRcntSet();
584}
585
586/******************************************************************************/
587
588s32 psxRcntFreeze( void *f, s32 Mode )
589{
590 u32 spuSyncCount = 0;
591 u32 count;
592 s32 i;
593
594 gzfreeze( &rcnts, sizeof(Rcnt) * CounterQuantity );
595 gzfreeze( &hSyncCount, sizeof(hSyncCount) );
596 gzfreeze( &spuSyncCount, sizeof(spuSyncCount) );
597 gzfreeze( &psxRegs.psxNextCounter, sizeof(psxRegs.psxNextCounter) );
598 gzfreeze( &psxRegs.psxNextsCounter, sizeof(psxRegs.psxNextsCounter) );
599
600 if (Mode == 0)
601 {
602 rcnts[3].rate = 1;
603 for( i = 0; i < CounterQuantity - 1; ++i )
604 {
605 _psxRcntWmode( i, rcnts[i].mode );
606 count = (psxRegs.cycle - rcnts[i].cycleStart) / rcnts[i].rate;
607 if (count > 0x1000)
608 _psxRcntWcount( i, count & 0xffff );
609 }
610 scheduleRcntBase();
611 psxRcntSet();
612 }
613
614 return 0;
615}
616
617/******************************************************************************/
618// vim:ts=4:shiftwidth=4:expandtab