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