frontend: enable SPUIRQWait by default
[pcsx_rearmed.git] / plugins / dfxvideo / gpu.c
CommitLineData
ef79bbde
P
1/***************************************************************************
2 gpu.c - description
3 -------------------
4 begin : Sun Oct 28 2001
5 copyright : (C) 2001 by Pete Bernert
6 email : BlackDove@addcom.de
7 ***************************************************************************/
8/***************************************************************************
9 * *
10 * This program is free software; you can redistribute it and/or modify *
11 * it under the terms of the GNU General Public License as published by *
12 * the Free Software Foundation; either version 2 of the License, or *
13 * (at your option) any later version. See also the license.txt file for *
14 * additional informations. *
15 * *
16 ***************************************************************************/
17
ef79bbde 18#include "gpu.h"
ef79bbde
P
19#include "stdint.h"
20#include "psemu_plugin_defs.h"
ef79bbde
P
21
22////////////////////////////////////////////////////////////////////////
23// memory image of the PSX vram
24////////////////////////////////////////////////////////////////////////
25
26unsigned char *psxVSecure;
27unsigned char *psxVub;
28signed char *psxVsb;
29unsigned short *psxVuw;
30unsigned short *psxVuw_eom;
31signed short *psxVsw;
a96a5eb2 32uint32_t *psxVul;
ef79bbde
P
33int32_t *psxVsl;
34
35////////////////////////////////////////////////////////////////////////
36// GPU globals
37////////////////////////////////////////////////////////////////////////
38
39static long lGPUdataRet;
40long lGPUstatusRet;
a96a5eb2 41uint32_t ulStatusControl[256];
ef79bbde
P
42
43static uint32_t gpuDataM[256];
44static unsigned char gpuCommand = 0;
45static long gpuDataC = 0;
46static long gpuDataP = 0;
47
48VRAMLoad_t VRAMWrite;
49VRAMLoad_t VRAMRead;
50DATAREGISTERMODES DataWriteMode;
51DATAREGISTERMODES DataReadMode;
52
53BOOL bSkipNextFrame = FALSE;
54DWORD dwLaceCnt=0;
ef79bbde
P
55short sDispWidths[8] = {256,320,512,640,368,384,512,640};
56PSXDisplay_t PSXDisplay;
57PSXDisplay_t PreviousPSXDisplay;
58long lSelectedSlot=0;
ef79bbde
P
59BOOL bDoLazyUpdate=FALSE;
60uint32_t lGPUInfoVals[16];
61static int iFakePrimBusy=0;
62
63////////////////////////////////////////////////////////////////////////
64// some misc external display funcs
65////////////////////////////////////////////////////////////////////////
66
67#include <time.h>
ef79bbde 68
a96a5eb2 69// FPS library
70#include "fps.c"
ef79bbde 71
ef79bbde
P
72
73////////////////////////////////////////////////////////////////////////
a96a5eb2 74// sets all kind of act fixes
ef79bbde
P
75////////////////////////////////////////////////////////////////////////
76
a96a5eb2 77static void SetFixes(void)
78 {
79 if(dwActFixes&0x02) sDispWidths[4]=384;
80 else sDispWidths[4]=368;
81 }
ef79bbde
P
82
83////////////////////////////////////////////////////////////////////////
84// INIT, will be called after lib load... well, just do some var init...
85////////////////////////////////////////////////////////////////////////
86
a96a5eb2 87long CALLBACK GPUinit(void) // GPU INIT
ef79bbde
P
88{
89 memset(ulStatusControl,0,256*sizeof(uint32_t)); // init save state scontrol field
90
a96a5eb2 91 psxVSecure = (unsigned char *)malloc((512*2)*1024 + (1024*1024)); // always alloc one extra MB for soft drawing funcs security
ef79bbde
P
92 if (!psxVSecure)
93 return -1;
94
95 //!!! ATTENTION !!!
96 psxVub=psxVSecure + 512 * 1024; // security offset into double sized psx vram!
97
98 psxVsb=(signed char *)psxVub; // different ways of accessing PSX VRAM
99 psxVsw=(signed short *)psxVub;
100 psxVsl=(int32_t *)psxVub;
101 psxVuw=(unsigned short *)psxVub;
102 psxVul=(uint32_t *)psxVub;
103
a96a5eb2 104 psxVuw_eom=psxVuw+1024*512; // pre-calc of end of vram
ef79bbde 105
a96a5eb2 106 memset(psxVSecure,0x00,(512*2)*1024 + (1024*1024));
ef79bbde
P
107 memset(lGPUInfoVals,0x00,16*sizeof(uint32_t));
108
ef79bbde
P
109 PSXDisplay.RGB24 = FALSE; // init some stuff
110 PSXDisplay.Interlaced = FALSE;
111 PSXDisplay.DrawOffset.x = 0;
112 PSXDisplay.DrawOffset.y = 0;
113 PSXDisplay.DisplayMode.x= 320;
114 PSXDisplay.DisplayMode.y= 240;
115 PreviousPSXDisplay.DisplayMode.x= 320;
116 PreviousPSXDisplay.DisplayMode.y= 240;
117 PSXDisplay.Disabled = FALSE;
118 PreviousPSXDisplay.Range.x0 =0;
119 PreviousPSXDisplay.Range.y0 =0;
120 PSXDisplay.Range.x0=0;
121 PSXDisplay.Range.x1=0;
122 PreviousPSXDisplay.DisplayModeNew.y=0;
123 PSXDisplay.Double = 1;
124 lGPUdataRet = 0x400;
125
126 DataWriteMode = DR_NORMAL;
127
128 // Reset transfer values, to prevent mis-transfer of data
129 memset(&VRAMWrite, 0, sizeof(VRAMLoad_t));
130 memset(&VRAMRead, 0, sizeof(VRAMLoad_t));
131
132 // device initialised already !
133 lGPUstatusRet = 0x14802000;
134 GPUIsIdle;
135 GPUIsReadyForCommands;
136 bDoVSyncUpdate = TRUE;
137
138 return 0;
139}
140
141////////////////////////////////////////////////////////////////////////
142// Here starts all...
143////////////////////////////////////////////////////////////////////////
144
145
146long GPUopen(unsigned long * disp,char * CapText,char * CfgFile)
147{
148 unsigned long d;
a96a5eb2 149
150 SetFixes();
ef79bbde
P
151
152 InitFPS();
153
ef79bbde
P
154 bDoVSyncUpdate = TRUE;
155
156 d=ulInitDisplay(); // setup x
157
158 if(disp)
159 *disp=d; // wanna x pointer? ok
160
161 if(d) return 0;
162 return -1;
163}
164
165
166////////////////////////////////////////////////////////////////////////
167// time to leave...
168////////////////////////////////////////////////////////////////////////
169
170long CALLBACK GPUclose() // GPU CLOSE
171{
ef79bbde
P
172 CloseDisplay(); // shutdown direct draw
173
174 return 0;
175}
176
177////////////////////////////////////////////////////////////////////////
178// I shot the sheriff
179////////////////////////////////////////////////////////////////////////
180
a96a5eb2 181long CALLBACK GPUshutdown(void) // GPU SHUTDOWN
ef79bbde 182{
a96a5eb2 183 CloseDisplay(); // shutdown direct draw
ef79bbde 184 free(psxVSecure);
ef79bbde
P
185 return 0; // nothinh to do
186}
187
188////////////////////////////////////////////////////////////////////////
189// Update display (swap buffers)
190////////////////////////////////////////////////////////////////////////
191
a96a5eb2 192static void updateDisplay(void) // UPDATE DISPLAY
ef79bbde
P
193{
194 if(PSXDisplay.Disabled) // disable?
195 {
ef79bbde
P
196 return; // -> and bye
197 }
198
199 if(dwActFixes&32) // pc fps calculation fix
200 {
201 if(UseFrameLimit) PCFrameCap(); // -> brake
a96a5eb2 202 if(UseFrameSkip) PCcalcfps();
ef79bbde
P
203 }
204
205 if(UseFrameSkip) // skip ?
206 {
207 if(!bSkipNextFrame) DoBufferSwap(); // -> to skip or not to skip
208 if(dwActFixes&0xa0) // -> pc fps calculation fix/old skipping fix
209 {
210 if((fps_skip < fFrameRateHz) && !(bSkipNextFrame)) // -> skip max one in a row
211 {bSkipNextFrame = TRUE; fps_skip=fFrameRateHz;}
212 else bSkipNextFrame = FALSE;
213 }
214 else FrameSkip();
215 }
216 else // no skip ?
217 {
0d8f5b89 218 bSkipNextFrame = FALSE;
ef79bbde
P
219 DoBufferSwap(); // -> swap
220 }
221}
222
223////////////////////////////////////////////////////////////////////////
224// roughly emulated screen centering bits... not complete !!!
225////////////////////////////////////////////////////////////////////////
226
227void ChangeDispOffsetsX(void) // X CENTER
228{
229 long lx,l;
230
231 if(!PSXDisplay.Range.x1) return;
232
233 l=PreviousPSXDisplay.DisplayMode.x;
234
235 l*=(long)PSXDisplay.Range.x1;
236 l/=2560;lx=l;l&=0xfffffff8;
237
238 if(l==PreviousPSXDisplay.Range.y1) return; // abusing range.y1 for
239 PreviousPSXDisplay.Range.y1=(short)l; // storing last x range and test
240
241 if(lx>=PreviousPSXDisplay.DisplayMode.x)
242 {
243 PreviousPSXDisplay.Range.x1=
244 (short)PreviousPSXDisplay.DisplayMode.x;
245 PreviousPSXDisplay.Range.x0=0;
246 }
247 else
248 {
249 PreviousPSXDisplay.Range.x1=(short)l;
250
251 PreviousPSXDisplay.Range.x0=
252 (PSXDisplay.Range.x0-500)/8;
253
254 if(PreviousPSXDisplay.Range.x0<0)
255 PreviousPSXDisplay.Range.x0=0;
256
257 if((PreviousPSXDisplay.Range.x0+lx)>
258 PreviousPSXDisplay.DisplayMode.x)
259 {
260 PreviousPSXDisplay.Range.x0=
261 (short)(PreviousPSXDisplay.DisplayMode.x-lx);
262 PreviousPSXDisplay.Range.x0+=2; //???
263
264 PreviousPSXDisplay.Range.x1+=(short)(lx-l);
265
266 PreviousPSXDisplay.Range.x1-=2; // makes linux stretching easier
267
268 }
269
ef79bbde
P
270 // some linux alignment security
271 PreviousPSXDisplay.Range.x0=PreviousPSXDisplay.Range.x0>>1;
272 PreviousPSXDisplay.Range.x0=PreviousPSXDisplay.Range.x0<<1;
273 PreviousPSXDisplay.Range.x1=PreviousPSXDisplay.Range.x1>>1;
274 PreviousPSXDisplay.Range.x1=PreviousPSXDisplay.Range.x1<<1;
275
ef79bbde
P
276 DoClearScreenBuffer();
277 }
278
279 bDoVSyncUpdate=TRUE;
280}
281
282////////////////////////////////////////////////////////////////////////
283
284void ChangeDispOffsetsY(void) // Y CENTER
285{
286 int iT,iO=PreviousPSXDisplay.Range.y0;
287 int iOldYOffset=PreviousPSXDisplay.DisplayModeNew.y;
288
289// new
290
a96a5eb2 291 if((PreviousPSXDisplay.DisplayModeNew.x+PSXDisplay.DisplayModeNew.y)>512)
ef79bbde 292 {
a96a5eb2 293 int dy1=512-PreviousPSXDisplay.DisplayModeNew.x;
294 int dy2=(PreviousPSXDisplay.DisplayModeNew.x+PSXDisplay.DisplayModeNew.y)-512;
ef79bbde
P
295
296 if(dy1>=dy2)
297 {
298 PreviousPSXDisplay.DisplayModeNew.y=-dy2;
299 }
300 else
301 {
302 PSXDisplay.DisplayPosition.y=0;
303 PreviousPSXDisplay.DisplayModeNew.y=-dy1;
304 }
305 }
306 else PreviousPSXDisplay.DisplayModeNew.y=0;
307
308// eon
309
310 if(PreviousPSXDisplay.DisplayModeNew.y!=iOldYOffset) // if old offset!=new offset: recalc height
311 {
312 PSXDisplay.Height = PSXDisplay.Range.y1 -
313 PSXDisplay.Range.y0 +
314 PreviousPSXDisplay.DisplayModeNew.y;
315 PSXDisplay.DisplayModeNew.y=PSXDisplay.Height*PSXDisplay.Double;
316 }
317
318//
319
320 if(PSXDisplay.PAL) iT=48; else iT=28;
321
322 if(PSXDisplay.Range.y0>=iT)
323 {
324 PreviousPSXDisplay.Range.y0=
325 (short)((PSXDisplay.Range.y0-iT-4)*PSXDisplay.Double);
326 if(PreviousPSXDisplay.Range.y0<0)
327 PreviousPSXDisplay.Range.y0=0;
328 PSXDisplay.DisplayModeNew.y+=
329 PreviousPSXDisplay.Range.y0;
330 }
331 else
332 PreviousPSXDisplay.Range.y0=0;
333
334 if(iO!=PreviousPSXDisplay.Range.y0)
335 {
336 DoClearScreenBuffer();
337 }
338}
339
340////////////////////////////////////////////////////////////////////////
341// check if update needed
342////////////////////////////////////////////////////////////////////////
343
a96a5eb2 344static void updateDisplayIfChanged(void) // UPDATE DISPLAY IF CHANGED
ef79bbde
P
345{
346 if ((PSXDisplay.DisplayMode.y == PSXDisplay.DisplayModeNew.y) &&
347 (PSXDisplay.DisplayMode.x == PSXDisplay.DisplayModeNew.x))
348 {
349 if((PSXDisplay.RGB24 == PSXDisplay.RGB24New) &&
350 (PSXDisplay.Interlaced == PSXDisplay.InterlacedNew)) return;
351 }
352
353 PSXDisplay.RGB24 = PSXDisplay.RGB24New; // get new infos
354
355 PSXDisplay.DisplayMode.y = PSXDisplay.DisplayModeNew.y;
356 PSXDisplay.DisplayMode.x = PSXDisplay.DisplayModeNew.x;
357 PreviousPSXDisplay.DisplayMode.x= // previous will hold
358 min(640,PSXDisplay.DisplayMode.x); // max 640x512... that's
359 PreviousPSXDisplay.DisplayMode.y= // the size of my
360 min(512,PSXDisplay.DisplayMode.y); // back buffer surface
361 PSXDisplay.Interlaced = PSXDisplay.InterlacedNew;
362
363 PSXDisplay.DisplayEnd.x= // calc end of display
364 PSXDisplay.DisplayPosition.x+ PSXDisplay.DisplayMode.x;
365 PSXDisplay.DisplayEnd.y=
366 PSXDisplay.DisplayPosition.y+ PSXDisplay.DisplayMode.y+PreviousPSXDisplay.DisplayModeNew.y;
367 PreviousPSXDisplay.DisplayEnd.x=
368 PreviousPSXDisplay.DisplayPosition.x+ PSXDisplay.DisplayMode.x;
369 PreviousPSXDisplay.DisplayEnd.y=
370 PreviousPSXDisplay.DisplayPosition.y+ PSXDisplay.DisplayMode.y+PreviousPSXDisplay.DisplayModeNew.y;
371
372 ChangeDispOffsetsX();
373
374 if(iFrameLimit==2) SetAutoFrameCap(); // -> set it
375
376 if(UseFrameSkip) updateDisplay(); // stupid stuff when frame skipping enabled
377}
378
ef79bbde
P
379////////////////////////////////////////////////////////////////////////
380// update lace is called evry VSync
381////////////////////////////////////////////////////////////////////////
382
383void CALLBACK GPUupdateLace(void) // VSYNC
384{
385 if(!(dwActFixes&1))
386 lGPUstatusRet^=0x80000000; // odd/even bit
387
dc40e780 388 //pcsx-rearmed: removed, this is handled by core
72228559 389 //if(!(dwActFixes&32)) // std fps limitation?
390 // CheckFrameRate();
ef79bbde
P
391
392 if(PSXDisplay.Interlaced) // interlaced mode?
393 {
394 if(bDoVSyncUpdate && PSXDisplay.DisplayMode.x>0 && PSXDisplay.DisplayMode.y>0)
395 {
396 updateDisplay();
397 }
398 }
399 else // non-interlaced?
400 {
401 if(dwActFixes&64) // lazy screen update fix
402 {
403 if(bDoLazyUpdate && !UseFrameSkip)
404 updateDisplay();
405 bDoLazyUpdate=FALSE;
406 }
407 else
408 {
409 if(bDoVSyncUpdate && !UseFrameSkip) // some primitives drawn?
410 updateDisplay(); // -> update display
411 }
412 }
ef79bbde
P
413 bDoVSyncUpdate=FALSE; // vsync done
414}
415
416////////////////////////////////////////////////////////////////////////
417// process read request from GPU status register
418////////////////////////////////////////////////////////////////////////
419
420
421uint32_t CALLBACK GPUreadStatus(void) // READ STATUS
422{
423 if(dwActFixes&1)
424 {
425 static int iNumRead=0; // odd/even hack
426 if((iNumRead++)==2)
427 {
428 iNumRead=0;
429 lGPUstatusRet^=0x80000000; // interlaced bit toggle... we do it on every 3 read status... needed by some games (like ChronoCross) with old epsxe versions (1.5.2 and older)
430 }
431 }
432
433 if(iFakePrimBusy) // 27.10.2007 - PETE : emulating some 'busy' while drawing... pfff
434 {
435 iFakePrimBusy--;
436
437 if(iFakePrimBusy&1) // we do a busy-idle-busy-idle sequence after/while drawing prims
438 {
439 GPUIsBusy;
440 GPUIsNotReadyForCommands;
441 }
442 else
443 {
444 GPUIsIdle;
445 GPUIsReadyForCommands;
446 }
447 }
448 return lGPUstatusRet;
449}
450
451////////////////////////////////////////////////////////////////////////
452// processes data send to GPU status register
453// these are always single packet commands.
454////////////////////////////////////////////////////////////////////////
455
456void CALLBACK GPUwriteStatus(uint32_t gdata) // WRITE STATUS
457{
458 uint32_t lCommand=(gdata>>24)&0xff;
459
460 ulStatusControl[lCommand]=gdata; // store command for freezing
461
462 switch(lCommand)
463 {
464 //--------------------------------------------------//
465 // reset gpu
466 case 0x00:
467 memset(lGPUInfoVals,0x00,16*sizeof(uint32_t));
468 lGPUstatusRet=0x14802000;
469 PSXDisplay.Disabled=1;
470 DataWriteMode=DataReadMode=DR_NORMAL;
471 PSXDisplay.DrawOffset.x=PSXDisplay.DrawOffset.y=0;
472 drawX=drawY=0;drawW=drawH=0;
473 sSetMask=0;lSetMask=0;bCheckMask=FALSE;
474 usMirror=0;
475 GlobalTextAddrX=0;GlobalTextAddrY=0;
476 GlobalTextTP=0;GlobalTextABR=0;
477 PSXDisplay.RGB24=FALSE;
478 PSXDisplay.Interlaced=FALSE;
479 bUsingTWin = FALSE;
480 return;
481 //--------------------------------------------------//
482 // dis/enable display
483 case 0x03:
484
485 PreviousPSXDisplay.Disabled = PSXDisplay.Disabled;
486 PSXDisplay.Disabled = (gdata & 1);
487
488 if(PSXDisplay.Disabled)
489 lGPUstatusRet|=GPUSTATUS_DISPLAYDISABLED;
490 else lGPUstatusRet&=~GPUSTATUS_DISPLAYDISABLED;
491 return;
492
493 //--------------------------------------------------//
494 // setting transfer mode
495 case 0x04:
496 gdata &= 0x03; // Only want the lower two bits
497
498 DataWriteMode=DataReadMode=DR_NORMAL;
499 if(gdata==0x02) DataWriteMode=DR_VRAMTRANSFER;
500 if(gdata==0x03) DataReadMode =DR_VRAMTRANSFER;
501 lGPUstatusRet&=~GPUSTATUS_DMABITS; // Clear the current settings of the DMA bits
502 lGPUstatusRet|=(gdata << 29); // Set the DMA bits according to the received data
503
504 return;
505 //--------------------------------------------------//
506 // setting display position
507 case 0x05:
508 {
509 PreviousPSXDisplay.DisplayPosition.x = PSXDisplay.DisplayPosition.x;
510 PreviousPSXDisplay.DisplayPosition.y = PSXDisplay.DisplayPosition.y;
511
ef79bbde 512// new
a96a5eb2 513 PSXDisplay.DisplayPosition.y = (short)((gdata>>10)&0x1ff);
ef79bbde
P
514
515 // store the same val in some helper var, we need it on later compares
516 PreviousPSXDisplay.DisplayModeNew.x=PSXDisplay.DisplayPosition.y;
517
a96a5eb2 518 if((PSXDisplay.DisplayPosition.y+PSXDisplay.DisplayMode.y)>512)
ef79bbde 519 {
a96a5eb2 520 int dy1=512-PSXDisplay.DisplayPosition.y;
521 int dy2=(PSXDisplay.DisplayPosition.y+PSXDisplay.DisplayMode.y)-512;
ef79bbde
P
522
523 if(dy1>=dy2)
524 {
525 PreviousPSXDisplay.DisplayModeNew.y=-dy2;
526 }
527 else
528 {
529 PSXDisplay.DisplayPosition.y=0;
530 PreviousPSXDisplay.DisplayModeNew.y=-dy1;
531 }
532 }
533 else PreviousPSXDisplay.DisplayModeNew.y=0;
534// eon
535
536 PSXDisplay.DisplayPosition.x = (short)(gdata & 0x3ff);
537 PSXDisplay.DisplayEnd.x=
538 PSXDisplay.DisplayPosition.x+ PSXDisplay.DisplayMode.x;
539 PSXDisplay.DisplayEnd.y=
540 PSXDisplay.DisplayPosition.y+ PSXDisplay.DisplayMode.y + PreviousPSXDisplay.DisplayModeNew.y;
541 PreviousPSXDisplay.DisplayEnd.x=
542 PreviousPSXDisplay.DisplayPosition.x+ PSXDisplay.DisplayMode.x;
543 PreviousPSXDisplay.DisplayEnd.y=
544 PreviousPSXDisplay.DisplayPosition.y+ PSXDisplay.DisplayMode.y + PreviousPSXDisplay.DisplayModeNew.y;
545
546 bDoVSyncUpdate=TRUE;
547
548 if (!(PSXDisplay.Interlaced)) // stupid frame skipping option
549 {
550 if(UseFrameSkip) updateDisplay();
551 if(dwActFixes&64) bDoLazyUpdate=TRUE;
552 }
553 }return;
554 //--------------------------------------------------//
555 // setting width
556 case 0x06:
557
558 PSXDisplay.Range.x0=(short)(gdata & 0x7ff);
559 PSXDisplay.Range.x1=(short)((gdata>>12) & 0xfff);
560
561 PSXDisplay.Range.x1-=PSXDisplay.Range.x0;
562
563 ChangeDispOffsetsX();
564
565 return;
566 //--------------------------------------------------//
567 // setting height
568 case 0x07:
569 {
570
571 PSXDisplay.Range.y0=(short)(gdata & 0x3ff);
572 PSXDisplay.Range.y1=(short)((gdata>>10) & 0x3ff);
573
574 PreviousPSXDisplay.Height = PSXDisplay.Height;
575
576 PSXDisplay.Height = PSXDisplay.Range.y1 -
577 PSXDisplay.Range.y0 +
578 PreviousPSXDisplay.DisplayModeNew.y;
579
580 if(PreviousPSXDisplay.Height!=PSXDisplay.Height)
581 {
582 PSXDisplay.DisplayModeNew.y=PSXDisplay.Height*PSXDisplay.Double;
583
584 ChangeDispOffsetsY();
585
586 updateDisplayIfChanged();
587 }
588 return;
589 }
590 //--------------------------------------------------//
591 // setting display infos
592 case 0x08:
593
594 PSXDisplay.DisplayModeNew.x =
595 sDispWidths[(gdata & 0x03) | ((gdata & 0x40) >> 4)];
596
597 if (gdata&0x04) PSXDisplay.Double=2;
598 else PSXDisplay.Double=1;
599
600 PSXDisplay.DisplayModeNew.y = PSXDisplay.Height*PSXDisplay.Double;
601
602 ChangeDispOffsetsY();
603
604 PSXDisplay.PAL = (gdata & 0x08)?TRUE:FALSE; // if 1 - PAL mode, else NTSC
605 PSXDisplay.RGB24New = (gdata & 0x10)?TRUE:FALSE; // if 1 - TrueColor
606 PSXDisplay.InterlacedNew = (gdata & 0x20)?TRUE:FALSE; // if 1 - Interlace
607
608 lGPUstatusRet&=~GPUSTATUS_WIDTHBITS; // Clear the width bits
609 lGPUstatusRet|=
610 (((gdata & 0x03) << 17) |
611 ((gdata & 0x40) << 10)); // Set the width bits
612
613 if(PSXDisplay.InterlacedNew)
614 {
615 if(!PSXDisplay.Interlaced)
616 {
617 PreviousPSXDisplay.DisplayPosition.x = PSXDisplay.DisplayPosition.x;
618 PreviousPSXDisplay.DisplayPosition.y = PSXDisplay.DisplayPosition.y;
619 }
620 lGPUstatusRet|=GPUSTATUS_INTERLACED;
621 }
622 else lGPUstatusRet&=~GPUSTATUS_INTERLACED;
623
624 if (PSXDisplay.PAL)
625 lGPUstatusRet|=GPUSTATUS_PAL;
626 else lGPUstatusRet&=~GPUSTATUS_PAL;
627
628 if (PSXDisplay.Double==2)
629 lGPUstatusRet|=GPUSTATUS_DOUBLEHEIGHT;
630 else lGPUstatusRet&=~GPUSTATUS_DOUBLEHEIGHT;
631
632 if (PSXDisplay.RGB24New)
633 lGPUstatusRet|=GPUSTATUS_RGB24;
634 else lGPUstatusRet&=~GPUSTATUS_RGB24;
635
636 updateDisplayIfChanged();
637
638 return;
639 //--------------------------------------------------//
640 // ask about GPU version and other stuff
641 case 0x10:
642
643 gdata&=0xff;
644
645 switch(gdata)
646 {
647 case 0x02:
648 lGPUdataRet=lGPUInfoVals[INFO_TW]; // tw infos
649 return;
650 case 0x03:
651 lGPUdataRet=lGPUInfoVals[INFO_DRAWSTART]; // draw start
652 return;
653 case 0x04:
654 lGPUdataRet=lGPUInfoVals[INFO_DRAWEND]; // draw end
655 return;
656 case 0x05:
657 case 0x06:
658 lGPUdataRet=lGPUInfoVals[INFO_DRAWOFF]; // draw offset
659 return;
660 case 0x07:
a96a5eb2 661 lGPUdataRet=0x02; // gpu type
ef79bbde
P
662 return;
663 case 0x08:
664 case 0x0F: // some bios addr?
665 lGPUdataRet=0xBFC03720;
666 return;
667 }
668 return;
669 //--------------------------------------------------//
670 }
671}
672
673////////////////////////////////////////////////////////////////////////
674// vram read/write helpers, needed by LEWPY's optimized vram read/write :)
675////////////////////////////////////////////////////////////////////////
676
a96a5eb2 677static inline void FinishedVRAMWrite(void)
ef79bbde 678{
ef79bbde
P
679 // Set register to NORMAL operation
680 DataWriteMode = DR_NORMAL;
681 // Reset transfer values, to prevent mis-transfer of data
682 VRAMWrite.x = 0;
683 VRAMWrite.y = 0;
684 VRAMWrite.Width = 0;
685 VRAMWrite.Height = 0;
686 VRAMWrite.ColsRemaining = 0;
687 VRAMWrite.RowsRemaining = 0;
688}
689
a96a5eb2 690static inline void FinishedVRAMRead(void)
ef79bbde
P
691{
692 // Set register to NORMAL operation
693 DataReadMode = DR_NORMAL;
694 // Reset transfer values, to prevent mis-transfer of data
695 VRAMRead.x = 0;
696 VRAMRead.y = 0;
697 VRAMRead.Width = 0;
698 VRAMRead.Height = 0;
699 VRAMRead.ColsRemaining = 0;
700 VRAMRead.RowsRemaining = 0;
701
702 // Indicate GPU is no longer ready for VRAM data in the STATUS REGISTER
703 lGPUstatusRet&=~GPUSTATUS_READYFORVRAM;
704}
705
706////////////////////////////////////////////////////////////////////////
707// core read from vram
708////////////////////////////////////////////////////////////////////////
709
710void CALLBACK GPUreadDataMem(uint32_t * pMem, int iSize)
711{
712 int i;
713
714 if(DataReadMode!=DR_VRAMTRANSFER) return;
715
716 GPUIsBusy;
717
718 // adjust read ptr, if necessary
719 while(VRAMRead.ImagePtr>=psxVuw_eom)
a96a5eb2 720 VRAMRead.ImagePtr-=512*1024;
ef79bbde 721 while(VRAMRead.ImagePtr<psxVuw)
a96a5eb2 722 VRAMRead.ImagePtr+=512*1024;
ef79bbde
P
723
724 for(i=0;i<iSize;i++)
725 {
726 // do 2 seperate 16bit reads for compatibility (wrap issues)
727 if ((VRAMRead.ColsRemaining > 0) && (VRAMRead.RowsRemaining > 0))
728 {
729 // lower 16 bit
730 lGPUdataRet=(uint32_t)GETLE16(VRAMRead.ImagePtr);
731
732 VRAMRead.ImagePtr++;
a96a5eb2 733 if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=512*1024;
ef79bbde
P
734 VRAMRead.RowsRemaining --;
735
736 if(VRAMRead.RowsRemaining<=0)
737 {
738 VRAMRead.RowsRemaining = VRAMRead.Width;
739 VRAMRead.ColsRemaining--;
740 VRAMRead.ImagePtr += 1024 - VRAMRead.Width;
a96a5eb2 741 if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=512*1024;
ef79bbde
P
742 }
743
744 // higher 16 bit (always, even if it's an odd width)
745 lGPUdataRet|=(uint32_t)GETLE16(VRAMRead.ImagePtr)<<16;
746 PUTLE32(pMem, lGPUdataRet); pMem++;
747
748 if(VRAMRead.ColsRemaining <= 0)
749 {FinishedVRAMRead();goto ENDREAD;}
750
751 VRAMRead.ImagePtr++;
a96a5eb2 752 if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=512*1024;
ef79bbde
P
753 VRAMRead.RowsRemaining--;
754 if(VRAMRead.RowsRemaining<=0)
755 {
756 VRAMRead.RowsRemaining = VRAMRead.Width;
757 VRAMRead.ColsRemaining--;
758 VRAMRead.ImagePtr += 1024 - VRAMRead.Width;
a96a5eb2 759 if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=512*1024;
ef79bbde
P
760 }
761 if(VRAMRead.ColsRemaining <= 0)
762 {FinishedVRAMRead();goto ENDREAD;}
763 }
764 else {FinishedVRAMRead();goto ENDREAD;}
765 }
766
767ENDREAD:
768 GPUIsIdle;
769}
770
771
772////////////////////////////////////////////////////////////////////////
773
774uint32_t CALLBACK GPUreadData(void)
775{
776 uint32_t l;
777 GPUreadDataMem(&l,1);
778 return lGPUdataRet;
779}
780
a96a5eb2 781// Software drawing function
782#include "soft.c"
783
784// PSX drawing primitives
785#include "prim.c"
786
ef79bbde
P
787////////////////////////////////////////////////////////////////////////
788// processes data send to GPU data register
789// extra table entries for fixing polyline troubles
790////////////////////////////////////////////////////////////////////////
791
a96a5eb2 792static const unsigned char primTableCX[256] =
ef79bbde
P
793{
794 // 00
795 0,0,3,0,0,0,0,0,
796 // 08
797 0,0,0,0,0,0,0,0,
798 // 10
799 0,0,0,0,0,0,0,0,
800 // 18
801 0,0,0,0,0,0,0,0,
802 // 20
803 4,4,4,4,7,7,7,7,
804 // 28
805 5,5,5,5,9,9,9,9,
806 // 30
807 6,6,6,6,9,9,9,9,
808 // 38
809 8,8,8,8,12,12,12,12,
810 // 40
811 3,3,3,3,0,0,0,0,
812 // 48
813// 5,5,5,5,6,6,6,6, // FLINE
814 254,254,254,254,254,254,254,254,
815 // 50
816 4,4,4,4,0,0,0,0,
817 // 58
818// 7,7,7,7,9,9,9,9, // GLINE
819 255,255,255,255,255,255,255,255,
820 // 60
821 3,3,3,3,4,4,4,4,
822 // 68
823 2,2,2,2,3,3,3,3, // 3=SPRITE1???
824 // 70
825 2,2,2,2,3,3,3,3,
826 // 78
827 2,2,2,2,3,3,3,3,
828 // 80
829 4,0,0,0,0,0,0,0,
830 // 88
831 0,0,0,0,0,0,0,0,
832 // 90
833 0,0,0,0,0,0,0,0,
834 // 98
835 0,0,0,0,0,0,0,0,
836 // a0
837 3,0,0,0,0,0,0,0,
838 // a8
839 0,0,0,0,0,0,0,0,
840 // b0
841 0,0,0,0,0,0,0,0,
842 // b8
843 0,0,0,0,0,0,0,0,
844 // c0
845 3,0,0,0,0,0,0,0,
846 // c8
847 0,0,0,0,0,0,0,0,
848 // d0
849 0,0,0,0,0,0,0,0,
850 // d8
851 0,0,0,0,0,0,0,0,
852 // e0
853 0,1,1,1,1,1,1,0,
854 // e8
855 0,0,0,0,0,0,0,0,
856 // f0
857 0,0,0,0,0,0,0,0,
858 // f8
859 0,0,0,0,0,0,0,0
860};
861
862void CALLBACK GPUwriteDataMem(uint32_t * pMem, int iSize)
863{
864 unsigned char command;
865 uint32_t gdata=0;
866 int i=0;
867 GPUIsBusy;
868 GPUIsNotReadyForCommands;
869
870STARTVRAM:
871
872 if(DataWriteMode==DR_VRAMTRANSFER)
873 {
874 BOOL bFinished=FALSE;
875
876 // make sure we are in vram
877 while(VRAMWrite.ImagePtr>=psxVuw_eom)
a96a5eb2 878 VRAMWrite.ImagePtr-=512*1024;
ef79bbde 879 while(VRAMWrite.ImagePtr<psxVuw)
a96a5eb2 880 VRAMWrite.ImagePtr+=512*1024;
ef79bbde
P
881
882 // now do the loop
883 while(VRAMWrite.ColsRemaining>0)
884 {
885 while(VRAMWrite.RowsRemaining>0)
886 {
887 if(i>=iSize) {goto ENDVRAM;}
888 i++;
889
890 gdata=GETLE32(pMem); pMem++;
891
892 PUTLE16(VRAMWrite.ImagePtr, (unsigned short)gdata); VRAMWrite.ImagePtr++;
a96a5eb2 893 if(VRAMWrite.ImagePtr>=psxVuw_eom) VRAMWrite.ImagePtr-=512*1024;
ef79bbde
P
894 VRAMWrite.RowsRemaining --;
895
896 if(VRAMWrite.RowsRemaining <= 0)
897 {
898 VRAMWrite.ColsRemaining--;
899 if (VRAMWrite.ColsRemaining <= 0) // last pixel is odd width
900 {
901 gdata=(gdata&0xFFFF)|(((uint32_t)GETLE16(VRAMWrite.ImagePtr))<<16);
902 FinishedVRAMWrite();
903 bDoVSyncUpdate=TRUE;
904 goto ENDVRAM;
905 }
906 VRAMWrite.RowsRemaining = VRAMWrite.Width;
907 VRAMWrite.ImagePtr += 1024 - VRAMWrite.Width;
908 }
909
910 PUTLE16(VRAMWrite.ImagePtr, (unsigned short)(gdata>>16)); VRAMWrite.ImagePtr++;
a96a5eb2 911 if(VRAMWrite.ImagePtr>=psxVuw_eom) VRAMWrite.ImagePtr-=512*1024;
ef79bbde
P
912 VRAMWrite.RowsRemaining --;
913 }
914
915 VRAMWrite.RowsRemaining = VRAMWrite.Width;
916 VRAMWrite.ColsRemaining--;
917 VRAMWrite.ImagePtr += 1024 - VRAMWrite.Width;
918 bFinished=TRUE;
919 }
920
921 FinishedVRAMWrite();
922 if(bFinished) bDoVSyncUpdate=TRUE;
923 }
924
925ENDVRAM:
926
927 if(DataWriteMode==DR_NORMAL)
928 {
929 void (* *primFunc)(unsigned char *);
930 if(bSkipNextFrame) primFunc=primTableSkip;
931 else primFunc=primTableJ;
932
933 for(;i<iSize;)
934 {
935 if(DataWriteMode==DR_VRAMTRANSFER) goto STARTVRAM;
936
937 gdata=GETLE32(pMem); pMem++; i++;
938
939 if(gpuDataC == 0)
940 {
941 command = (unsigned char)((gdata>>24) & 0xff);
942
943//if(command>=0xb0 && command<0xc0) auxprintf("b0 %x!!!!!!!!!\n",command);
944
945 if(primTableCX[command])
946 {
947 gpuDataC = primTableCX[command];
948 gpuCommand = command;
0d16cda2 949 PUTLE32_(&gpuDataM[0], gdata);
ef79bbde
P
950 gpuDataP = 1;
951 }
952 else continue;
953 }
954 else
955 {
0d16cda2 956 PUTLE32_(&gpuDataM[gpuDataP], gdata);
ef79bbde
P
957 if(gpuDataC>128)
958 {
959 if((gpuDataC==254 && gpuDataP>=3) ||
960 (gpuDataC==255 && gpuDataP>=4 && !(gpuDataP&1)))
961 {
962 if((gpuDataM[gpuDataP] & 0xF000F000) == 0x50005000)
963 gpuDataP=gpuDataC-1;
964 }
965 }
966 gpuDataP++;
967 }
968
969 if(gpuDataP == gpuDataC)
970 {
971 gpuDataC=gpuDataP=0;
972 primFunc[gpuCommand]((unsigned char *)gpuDataM);
a96a5eb2 973 if(dwActFixes&0x0400) // hack for emulating "gpu busy" in some games
974 iFakePrimBusy=4;
975 }
ef79bbde
P
976 }
977 }
978
979 lGPUdataRet=gdata;
980
981 GPUIsReadyForCommands;
982 GPUIsIdle;
983}
984
985////////////////////////////////////////////////////////////////////////
986
987void CALLBACK GPUwriteData(uint32_t gdata)
988{
0d16cda2 989 PUTLE32_(&gdata, gdata);
ef79bbde
P
990 GPUwriteDataMem(&gdata,1);
991}
992
ef79bbde
P
993////////////////////////////////////////////////////////////////////////
994// process gpu commands
995////////////////////////////////////////////////////////////////////////
996
997unsigned long lUsedAddr[3];
998
a96a5eb2 999static inline BOOL CheckForEndlessLoop(unsigned long laddr)
ef79bbde
P
1000{
1001 if(laddr==lUsedAddr[1]) return TRUE;
1002 if(laddr==lUsedAddr[2]) return TRUE;
1003
1004 if(laddr<lUsedAddr[0]) lUsedAddr[1]=laddr;
1005 else lUsedAddr[2]=laddr;
1006 lUsedAddr[0]=laddr;
1007 return FALSE;
1008}
1009
1010long CALLBACK GPUdmaChain(uint32_t * baseAddrL, uint32_t addr)
1011{
1012 uint32_t dmaMem;
1013 unsigned char * baseAddrB;
1014 short count;unsigned int DMACommandCounter = 0;
1015
1016 GPUIsBusy;
1017
1018 lUsedAddr[0]=lUsedAddr[1]=lUsedAddr[2]=0xffffff;
1019
1020 baseAddrB = (unsigned char*) baseAddrL;
1021
1022 do
1023 {
a96a5eb2 1024 addr&=0x1FFFFC;
ef79bbde
P
1025 if(DMACommandCounter++ > 2000000) break;
1026 if(CheckForEndlessLoop(addr)) break;
1027
1028 count = baseAddrB[addr+3];
1029
1030 dmaMem=addr+4;
1031
1032 if(count>0) GPUwriteDataMem(&baseAddrL[dmaMem>>2],count);
1033
1034 addr = GETLE32(&baseAddrL[addr>>2])&0xffffff;
1035 }
1036 while (addr != 0xffffff);
1037
1038 GPUIsIdle;
1039
1040 return 0;
1041}
1042
ef79bbde
P
1043////////////////////////////////////////////////////////////////////////
1044// Freeze
1045////////////////////////////////////////////////////////////////////////
1046
1047typedef struct GPUFREEZETAG
1048{
1049 uint32_t ulFreezeVersion; // should be always 1 for now (set by main emu)
1050 uint32_t ulStatus; // current gpu status
1051 uint32_t ulControl[256]; // latest control register values
1052 unsigned char psxVRam[1024*1024*2]; // current VRam image (full 2 MB for ZN)
1053} GPUFreeze_t;
1054
1055////////////////////////////////////////////////////////////////////////
1056
1057long CALLBACK GPUfreeze(uint32_t ulGetFreezeData,GPUFreeze_t * pF)
1058{
1059 //----------------------------------------------------//
1060 if(ulGetFreezeData==2) // 2: info, which save slot is selected? (just for display)
1061 {
1062 long lSlotNum=*((long *)pF);
1063 if(lSlotNum<0) return 0;
1064 if(lSlotNum>8) return 0;
1065 lSelectedSlot=lSlotNum+1;
ef79bbde
P
1066 return 1;
1067 }
1068 //----------------------------------------------------//
1069 if(!pF) return 0; // some checks
1070 if(pF->ulFreezeVersion!=1) return 0;
1071
1072 if(ulGetFreezeData==1) // 1: get data
1073 {
1074 pF->ulStatus=lGPUstatusRet;
1075 memcpy(pF->ulControl,ulStatusControl,256*sizeof(uint32_t));
a96a5eb2 1076 memcpy(pF->psxVRam, psxVub, 1024*512*2);
ef79bbde
P
1077
1078 return 1;
1079 }
1080
1081 if(ulGetFreezeData!=0) return 0; // 0: set data
1082
1083 lGPUstatusRet=pF->ulStatus;
1084 memcpy(ulStatusControl,pF->ulControl,256*sizeof(uint32_t));
a96a5eb2 1085 memcpy(psxVub, pF->psxVRam, 1024*512*2);
ef79bbde
P
1086
1087// RESET TEXTURE STORE HERE, IF YOU USE SOMETHING LIKE THAT
1088
1089 GPUwriteStatus(ulStatusControl[0]);
1090 GPUwriteStatus(ulStatusControl[1]);
1091 GPUwriteStatus(ulStatusControl[2]);
1092 GPUwriteStatus(ulStatusControl[3]);
1093 GPUwriteStatus(ulStatusControl[8]); // try to repair things
1094 GPUwriteStatus(ulStatusControl[6]);
1095 GPUwriteStatus(ulStatusControl[7]);
1096 GPUwriteStatus(ulStatusControl[5]);
1097 GPUwriteStatus(ulStatusControl[4]);
1098
1099 return 1;
1100}