frontend: update libpicofe, fix missed callbacks
[pcsx_rearmed.git] / libpcsxcore / psxcounters.c
CommitLineData
ef79bbde
P
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"
9a0a61d2 25#include "psxevents.h"
ddbaf678 26#include "gpu.h"
7d7672a5 27//#include "debug.h"
28#define DebugVSync()
ef79bbde
P
29
30/******************************************************************************/
31
ef79bbde
P
32enum
33{
11d23573 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
ef79bbde
P
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
1351a8fb 65static const u32 HSyncTotal[] = { 263, 314 };
66#define VBlankStart 240 // todo: depend on the actual GPU setting
ef79bbde 67
9f7ee52e 68#define VERBOSE_LEVEL 0
ef79bbde
P
69
70/******************************************************************************/
41e82ad4 71#ifdef DRC_DISABLE
b1be1eee 72Rcnt rcnts[ CounterQuantity ];
41e82ad4 73#endif
6ac061ec 74unsigned int hSyncCount = 0;
75unsigned int frame_counter = 0;
61ef5cf4 76static u32 hsync_steps = 0;
ef79bbde 77
ef79bbde
P
78/******************************************************************************/
79
4c8f1c25 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
1351a8fb 110static inline
111u32 lineCycles(void)
112{
4c8f1c25 113 // should be more like above, but our timing is already poor anyway
1351a8fb 114 if (Config.PsxType)
115 return PSXCLK / 50 / HSyncTotal[1];
116 else
117 return PSXCLK / 60 / HSyncTotal[0];
118}
119
ef79bbde
P
120static inline
121void setIrq( u32 irq )
122{
123 psxHu32ref(0x1070) |= SWAPu32(irq);
124}
125
126static
9f7ee52e 127void verboseLog( u32 level, const char *str, ... )
ef79bbde 128{
9f7ee52e 129#if VERBOSE_LEVEL > 0
3cf51e08 130 if( level <= VERBOSE_LEVEL )
ef79bbde
P
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
ab948f7e 139 printf( "%s", buf );
ef79bbde
P
140 fflush( stdout );
141 }
9f7ee52e 142#endif
ef79bbde
P
143}
144
145/******************************************************************************/
146
147static inline
148void _psxRcntWcount( u32 index, u32 value )
149{
20bfbac0 150 value &= 0xffff;
ef79bbde
P
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 {
8ca6b0a6 163 rcnts[index].cycle = 0x10000 * rcnts[index].rate;
ef79bbde
P
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;
61ef5cf4 175 if (rcnts[index].rate > 1)
176 count /= rcnts[index].rate;
ef79bbde 177
8ca6b0a6 178 if( count > 0x10000 )
ef79bbde 179 {
8ca6b0a6 180 verboseLog( 1, "[RCNT %i] rcount > 0x10000: %x\n", index, count );
ef79bbde 181 }
8ca6b0a6 182 count &= 0xffff;
ef79bbde
P
183
184 return count;
185}
186
a29f182f 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 {
1351a8fb 207 rcnts[index].rate = lineCycles();
a29f182f 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.
11d23573 225 if( (value & 7) == (RcSyncModeEnable | Rc2Stop) ||
226 (value & 7) == (RcSyncModeEnable | Rc2Stop2) )
a29f182f 227 {
228 rcnts[index].rate = 0xffffffff;
229 }
230 break;
231 }
232}
233
ef79bbde
P
234/******************************************************************************/
235
236static
237void psxRcntSet()
238{
239 s32 countToUpdate;
240 u32 i;
241
92dc6b2f 242 psxRegs.psxNextsCounter = psxRegs.cycle;
243 psxRegs.psxNextCounter = 0x7fffffff;
ef79bbde
P
244
245 for( i = 0; i < CounterQuantity; ++i )
246 {
92dc6b2f 247 countToUpdate = rcnts[i].cycle - (psxRegs.psxNextsCounter - rcnts[i].cycleStart);
ef79bbde
P
248
249 if( countToUpdate < 0 )
250 {
92dc6b2f 251 psxRegs.psxNextCounter = 0;
ef79bbde
P
252 break;
253 }
254
92dc6b2f 255 if( countToUpdate < (s32)psxRegs.psxNextCounter )
ef79bbde 256 {
92dc6b2f 257 psxRegs.psxNextCounter = countToUpdate;
ef79bbde
P
258 }
259 }
5b8c000f 260
92dc6b2f 261 set_event(PSXINT_RCNT, psxRegs.psxNextCounter);
ef79bbde
P
262}
263
264/******************************************************************************/
265
266static
267void psxRcntReset( u32 index )
268{
8ca6b0a6 269 u32 rcycles;
ef79bbde 270
53c361f0 271 rcnts[index].mode |= RcUnknown10;
272
ef79bbde
P
273 if( rcnts[index].counterState == CountToTarget )
274 {
8ca6b0a6 275 rcycles = psxRegs.cycle - rcnts[index].cycleStart;
ef79bbde 276 if( rcnts[index].mode & RcCountToTarget )
8ca6b0a6 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 }
ef79bbde
P
286
287 if( rcnts[index].mode & RcIrqOnTarget )
288 {
289 if( (rcnts[index].mode & RcIrqRegenerate) || (!rcnts[index].irqState) )
290 {
8ca6b0a6 291 verboseLog( 3, "[RCNT %i] irq\n", index );
ef79bbde
P
292 setIrq( rcnts[index].irq );
293 rcnts[index].irqState = 1;
294 }
295 }
296
297 rcnts[index].mode |= RcCountEqTarget;
53c361f0 298
8ca6b0a6 299 if( rcycles < 0x10000 * rcnts[index].rate )
53c361f0 300 return;
ef79bbde 301 }
53c361f0 302
303 if( rcnts[index].counterState == CountToOverflow )
ef79bbde 304 {
8ca6b0a6 305 rcycles = psxRegs.cycle - rcnts[index].cycleStart;
306 rcycles -= 0x10000 * rcnts[index].rate;
307
308 rcnts[index].cycleStart = psxRegs.cycle - rcycles;
ef79bbde 309
8ca6b0a6 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 }
ef79bbde
P
315
316 if( rcnts[index].mode & RcIrqOnOverflow )
317 {
318 if( (rcnts[index].mode & RcIrqRegenerate) || (!rcnts[index].irqState) )
319 {
8ca6b0a6 320 verboseLog( 3, "[RCNT %i] irq\n", index );
ef79bbde
P
321 setIrq( rcnts[index].irq );
322 rcnts[index].irqState = 1;
323 }
324 }
325
326 rcnts[index].mode |= RcOverflow;
327 }
ef79bbde
P
328}
329
ff2c2822 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 {
4c8f1c25 340 rcnts[3].cycle = frameCycles();
ff2c2822 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
ef79bbde
P
351void psxRcntUpdate()
352{
11d23573 353 u32 cycle, cycles_passed;
ef79bbde
P
354
355 cycle = psxRegs.cycle;
356
357 // rcnt 0.
11d23573 358 cycles_passed = cycle - rcnts[0].cycleStart;
359 while( cycles_passed >= rcnts[0].cycle )
ef79bbde 360 {
11d23573 361 if (((rcnts[0].mode & 7) == (RcSyncModeEnable | Rc01UnblankReset) ||
362 (rcnts[0].mode & 7) == (RcSyncModeEnable | Rc01UnblankReset2))
1351a8fb 363 && cycles_passed > lineCycles())
11d23573 364 {
1351a8fb 365 u32 q = cycles_passed / (lineCycles() + 1u);
366 rcnts[0].cycleStart += q * lineCycles();
11d23573 367 break;
368 }
369 else
370 psxRcntReset( 0 );
371
372 cycles_passed = cycle - rcnts[0].cycleStart;
ef79bbde
P
373 }
374
375 // rcnt 1.
e7851504 376 while( cycle - rcnts[1].cycleStart >= rcnts[1].cycle )
ef79bbde
P
377 {
378 psxRcntReset( 1 );
379 }
380
381 // rcnt 2.
e7851504 382 while( cycle - rcnts[2].cycleStart >= rcnts[2].cycle )
ef79bbde
P
383 {
384 psxRcntReset( 2 );
385 }
386
387 // rcnt base.
388 if( cycle - rcnts[3].cycleStart >= rcnts[3].cycle )
389 {
61ef5cf4 390 hSyncCount += hsync_steps;
ef79bbde 391
ef79bbde 392 // VSync irq.
0486fdc9 393 if( hSyncCount == VBlankStart )
ef79bbde 394 {
086adfff 395 HW_GPU_STATUS &= SWAP32(~PSXGPU_LCF);
72e5023f 396 GPU_vBlank( 1, 0 );
8bbbd091 397 setIrq( 0x01 );
398
399 EmuUpdate();
400 GPU_updateLace();
d618a240 401
402 if( SPU_async )
403 {
404 SPU_async( cycle, 1 );
405 }
ef79bbde
P
406 }
407
d014a471 408 // Update lace.
409 if( hSyncCount >= HSyncTotal[Config.PsxType] )
ef79bbde 410 {
1351a8fb 411 u32 status, field = 0;
4c8f1c25 412 rcnts[3].cycleStart += frameCycles();
ef79bbde 413 hSyncCount = 0;
ddbaf678 414 frame_counter++;
ef79bbde 415
0486fdc9 416 gpuSyncPluginSR();
db57cbb8 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);
f8896d18 425 if ((s32)(psxRegs.gpuIdleAfter - psxRegs.cycle) < 0)
426 psxRegs.gpuIdleAfter = psxRegs.cycle - 1; // prevent overflow
11d23573 427
1351a8fb 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)
11d23573 440 {
1351a8fb 441 // adjust to remove the rounding error
442 _psxRcntWcount(1, (psxRegs.cycle - rcnts[1].cycleStart) / rcnts[1].rate);
11d23573 443 }
ef79bbde 444 }
61ef5cf4 445
ff2c2822 446 scheduleRcntBase();
ef79bbde
P
447 }
448
95df1a04 449 psxRcntSet();
450
7a8d521f 451#if 0 //ndef NDEBUG
ef79bbde 452 DebugVSync();
61ef5cf4 453#endif
ef79bbde
P
454}
455
456/******************************************************************************/
457
458void psxRcntWcount( u32 index, u32 value )
459{
460 verboseLog( 2, "[RCNT %i] wcount: %x\n", index, value );
461
ef79bbde
P
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
a29f182f 470 _psxRcntWmode( index, value );
ef79bbde 471 _psxRcntWcount( index, 0 );
a29f182f 472
473 rcnts[index].irqState = 0;
ef79bbde
P
474 psxRcntSet();
475}
476
477void psxRcntWtarget( u32 index, u32 value )
478{
479 verboseLog( 1, "[RCNT %i] wtarget: %x\n", index, value );
480
ef79bbde
P
481 rcnts[index].target = value;
482
483 _psxRcntWcount( index, _psxRcntRcount( index ) );
484 psxRcntSet();
485}
486
487/******************************************************************************/
488
11d23573 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;
1351a8fb 498 //count = ((16u * count) % (16u * PSXCLK / 60 / 263)) / 16u;
499 count = count % lineCycles();
11d23573 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()
ef79bbde 523{
11d23573 524 u32 index = 2;
ef79bbde
P
525 u32 count;
526
ef79bbde
P
527 count = _psxRcntRcount( index );
528
11d23573 529 verboseLog( 2, "[RCNT 2] rcount: %04x m: %04x\n", count, rcnts[index].mode);
ef79bbde
P
530
531 return count;
532}
533
534u32 psxRcntRmode( u32 index )
535{
536 u16 mode;
537
ef79bbde
P
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;
ef79bbde
P
573
574 for( i = 0; i < CounterQuantity; ++i )
575 {
576 _psxRcntWcount( i, 0 );
577 }
578
c62b43c9 579 hSyncCount = 0;
61ef5cf4 580 hsync_steps = 1;
c62b43c9 581
1351a8fb 582 scheduleRcntBase();
ef79bbde
P
583 psxRcntSet();
584}
585
586/******************************************************************************/
587
496d88d4 588s32 psxRcntFreeze( void *f, s32 Mode )
ef79bbde 589{
d618a240 590 u32 spuSyncCount = 0;
d0af6d75 591 u32 count;
a29f182f 592 s32 i;
593
41e82ad4 594 gzfreeze( &rcnts, sizeof(Rcnt) * CounterQuantity );
ef79bbde
P
595 gzfreeze( &hSyncCount, sizeof(hSyncCount) );
596 gzfreeze( &spuSyncCount, sizeof(spuSyncCount) );
92dc6b2f 597 gzfreeze( &psxRegs.psxNextCounter, sizeof(psxRegs.psxNextCounter) );
598 gzfreeze( &psxRegs.psxNextsCounter, sizeof(psxRegs.psxNextsCounter) );
ef79bbde 599
61ef5cf4 600 if (Mode == 0)
a29f182f 601 {
e43c9382 602 rcnts[3].rate = 1;
b34d6a80 603 for( i = 0; i < CounterQuantity - 1; ++i )
d0af6d75 604 {
a29f182f 605 _psxRcntWmode( i, rcnts[i].mode );
d0af6d75 606 count = (psxRegs.cycle - rcnts[i].cycleStart) / rcnts[i].rate;
607 if (count > 0x1000)
608 _psxRcntWcount( i, count & 0xffff );
609 }
ff2c2822 610 scheduleRcntBase();
a29f182f 611 psxRcntSet();
a29f182f 612 }
4f55097d 613
ef79bbde
P
614 return 0;
615}
616
617/******************************************************************************/
ff2c2822 618// vim:ts=4:shiftwidth=4:expandtab