1 /***************************************************************************
4 begin : Sun Oct 28 2001
5 copyright : (C) 2001 by Pete Bernert
6 email : BlackDove@addcom.de
7 ***************************************************************************/
8 /***************************************************************************
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. *
16 ***************************************************************************/
20 #include "psemu_plugin_defs.h"
22 ////////////////////////////////////////////////////////////////////////
23 // memory image of the PSX vram
24 ////////////////////////////////////////////////////////////////////////
26 unsigned char *psxVSecure;
27 unsigned char *psxVub;
29 unsigned short *psxVuw;
30 unsigned short *psxVuw_eom;
35 ////////////////////////////////////////////////////////////////////////
37 ////////////////////////////////////////////////////////////////////////
39 static long lGPUdataRet;
41 uint32_t ulStatusControl[256];
43 static uint32_t gpuDataM[256];
44 static unsigned char gpuCommand = 0;
45 static long gpuDataC = 0;
46 static long gpuDataP = 0;
50 DATAREGISTERMODES DataWriteMode;
51 DATAREGISTERMODES DataReadMode;
53 BOOL bSkipNextFrame = FALSE;
54 BOOL fskip_frameReady;
55 DWORD lace_count_since_flip;
57 short sDispWidths[8] = {256,320,512,640,368,384,512,640};
58 PSXDisplay_t PSXDisplay;
59 PSXDisplay_t PreviousPSXDisplay;
61 BOOL bDoLazyUpdate=FALSE;
62 uint32_t lGPUInfoVals[16];
63 static int iFakePrimBusy=0;
64 static uint32_t vBlank=0;
66 ////////////////////////////////////////////////////////////////////////
67 // some misc external display funcs
68 ////////////////////////////////////////////////////////////////////////
76 ////////////////////////////////////////////////////////////////////////
77 // sets all kind of act fixes
78 ////////////////////////////////////////////////////////////////////////
80 static void SetFixes(void)
82 if(dwActFixes&0x02) sDispWidths[4]=384;
83 else sDispWidths[4]=368;
86 ////////////////////////////////////////////////////////////////////////
87 // INIT, will be called after lib load... well, just do some var init...
88 ////////////////////////////////////////////////////////////////////////
90 long CALLBACK GPUinit(void) // GPU INIT
92 memset(ulStatusControl,0,256*sizeof(uint32_t)); // init save state scontrol field
94 psxVSecure = (unsigned char *)malloc((512*2)*1024 + (1024*1024)); // always alloc one extra MB for soft drawing funcs security
99 psxVub=psxVSecure + 512 * 1024; // security offset into double sized psx vram!
101 psxVsb=(signed char *)psxVub; // different ways of accessing PSX VRAM
102 psxVsw=(signed short *)psxVub;
103 psxVsl=(int32_t *)psxVub;
104 psxVuw=(unsigned short *)psxVub;
105 psxVul=(uint32_t *)psxVub;
107 psxVuw_eom=psxVuw+1024*512; // pre-calc of end of vram
109 memset(psxVSecure,0x00,(512*2)*1024 + (1024*1024));
110 memset(lGPUInfoVals,0x00,16*sizeof(uint32_t));
112 PSXDisplay.RGB24 = FALSE; // init some stuff
113 PSXDisplay.Interlaced = FALSE;
114 PSXDisplay.DrawOffset.x = 0;
115 PSXDisplay.DrawOffset.y = 0;
116 PSXDisplay.DisplayMode.x= 320;
117 PSXDisplay.DisplayMode.y= 240;
118 PreviousPSXDisplay.DisplayMode.x= 320;
119 PreviousPSXDisplay.DisplayMode.y= 240;
120 PSXDisplay.Disabled = FALSE;
121 PreviousPSXDisplay.Range.x0 =0;
122 PreviousPSXDisplay.Range.y0 =0;
123 PSXDisplay.Range.x0=0;
124 PSXDisplay.Range.x1=0;
125 PreviousPSXDisplay.DisplayModeNew.y=0;
126 PSXDisplay.Double = 1;
129 DataWriteMode = DR_NORMAL;
131 // Reset transfer values, to prevent mis-transfer of data
132 memset(&VRAMWrite, 0, sizeof(VRAMLoad_t));
133 memset(&VRAMRead, 0, sizeof(VRAMLoad_t));
135 // device initialised already !
136 lGPUstatusRet = 0x14802000;
138 GPUIsReadyForCommands;
139 bDoVSyncUpdate = TRUE;
144 ////////////////////////////////////////////////////////////////////////
145 // Here starts all...
146 ////////////////////////////////////////////////////////////////////////
149 long GPUopen(unsigned long * disp,char * CapText,char * CfgFile)
157 bDoVSyncUpdate = TRUE;
159 d=ulInitDisplay(); // setup x
162 *disp=d; // wanna x pointer? ok
169 ////////////////////////////////////////////////////////////////////////
171 ////////////////////////////////////////////////////////////////////////
173 long CALLBACK GPUclose() // GPU CLOSE
175 CloseDisplay(); // shutdown direct draw
180 ////////////////////////////////////////////////////////////////////////
181 // I shot the sheriff
182 ////////////////////////////////////////////////////////////////////////
184 long CALLBACK GPUshutdown(void) // GPU SHUTDOWN
186 CloseDisplay(); // shutdown direct draw
188 return 0; // nothinh to do
191 ////////////////////////////////////////////////////////////////////////
192 // Update display (swap buffers)
193 ////////////////////////////////////////////////////////////////////////
195 static void updateDisplay(void) // UPDATE DISPLAY
197 if(PSXDisplay.Disabled) // disable?
199 return; // -> and bye
202 if(dwActFixes&32) // pc fps calculation fix
204 if(UseFrameLimit) PCFrameCap(); // -> brake
205 if(UseFrameSkip) PCcalcfps();
208 if(UseFrameSkip) // skip ?
212 DoBufferSwap(); // -> to skip or not to skip
213 fskip_frameReady=FALSE;
214 bDoVSyncUpdate=FALSE; // vsync done
219 bSkipNextFrame = FALSE;
220 DoBufferSwap(); // -> swap
221 bDoVSyncUpdate=FALSE; // vsync done
225 static void decideSkip(void)
230 lace_count_since_flip=0;
231 fskip_frameReady=!bSkipNextFrame;
233 if(dwActFixes&0xa0) // -> pc fps calculation fix/old skipping fix
235 if((fps_skip < fFrameRateHz) && !bSkipNextFrame) // -> skip max one in a row
236 {bSkipNextFrame = TRUE; fps_skip=fFrameRateHz;}
237 else bSkipNextFrame = FALSE;
242 ////////////////////////////////////////////////////////////////////////
243 // roughly emulated screen centering bits... not complete !!!
244 ////////////////////////////////////////////////////////////////////////
246 void ChangeDispOffsetsX(void) // X CENTER
250 if(!PSXDisplay.Range.x1) return;
252 l=PreviousPSXDisplay.DisplayMode.x;
254 l*=(long)PSXDisplay.Range.x1;
255 l/=2560;lx=l;l&=0xfffffff8;
257 if(l==PreviousPSXDisplay.Range.y1) return; // abusing range.y1 for
258 PreviousPSXDisplay.Range.y1=(short)l; // storing last x range and test
260 if(lx>=PreviousPSXDisplay.DisplayMode.x)
262 PreviousPSXDisplay.Range.x1=
263 (short)PreviousPSXDisplay.DisplayMode.x;
264 PreviousPSXDisplay.Range.x0=0;
268 PreviousPSXDisplay.Range.x1=(short)l;
270 PreviousPSXDisplay.Range.x0=
271 (PSXDisplay.Range.x0-500)/8;
273 if(PreviousPSXDisplay.Range.x0<0)
274 PreviousPSXDisplay.Range.x0=0;
276 if((PreviousPSXDisplay.Range.x0+lx)>
277 PreviousPSXDisplay.DisplayMode.x)
279 PreviousPSXDisplay.Range.x0=
280 (short)(PreviousPSXDisplay.DisplayMode.x-lx);
281 PreviousPSXDisplay.Range.x0+=2; //???
283 PreviousPSXDisplay.Range.x1+=(short)(lx-l);
285 PreviousPSXDisplay.Range.x1-=2; // makes linux stretching easier
289 // some linux alignment security
290 PreviousPSXDisplay.Range.x0=PreviousPSXDisplay.Range.x0>>1;
291 PreviousPSXDisplay.Range.x0=PreviousPSXDisplay.Range.x0<<1;
292 PreviousPSXDisplay.Range.x1=PreviousPSXDisplay.Range.x1>>1;
293 PreviousPSXDisplay.Range.x1=PreviousPSXDisplay.Range.x1<<1;
295 DoClearScreenBuffer();
301 ////////////////////////////////////////////////////////////////////////
303 void ChangeDispOffsetsY(void) // Y CENTER
305 int iT,iO=PreviousPSXDisplay.Range.y0;
306 int iOldYOffset=PreviousPSXDisplay.DisplayModeNew.y;
310 if((PreviousPSXDisplay.DisplayModeNew.x+PSXDisplay.DisplayModeNew.y)>512)
312 int dy1=512-PreviousPSXDisplay.DisplayModeNew.x;
313 int dy2=(PreviousPSXDisplay.DisplayModeNew.x+PSXDisplay.DisplayModeNew.y)-512;
317 PreviousPSXDisplay.DisplayModeNew.y=-dy2;
321 PSXDisplay.DisplayPosition.y=0;
322 PreviousPSXDisplay.DisplayModeNew.y=-dy1;
325 else PreviousPSXDisplay.DisplayModeNew.y=0;
329 if(PreviousPSXDisplay.DisplayModeNew.y!=iOldYOffset) // if old offset!=new offset: recalc height
331 PSXDisplay.Height = PSXDisplay.Range.y1 -
332 PSXDisplay.Range.y0 +
333 PreviousPSXDisplay.DisplayModeNew.y;
334 PSXDisplay.DisplayModeNew.y=PSXDisplay.Height*PSXDisplay.Double;
339 if(PSXDisplay.PAL) iT=48; else iT=28;
341 if(PSXDisplay.Range.y0>=iT)
343 PreviousPSXDisplay.Range.y0=
344 (short)((PSXDisplay.Range.y0-iT-4)*PSXDisplay.Double);
345 if(PreviousPSXDisplay.Range.y0<0)
346 PreviousPSXDisplay.Range.y0=0;
347 PSXDisplay.DisplayModeNew.y+=
348 PreviousPSXDisplay.Range.y0;
351 PreviousPSXDisplay.Range.y0=0;
353 if(iO!=PreviousPSXDisplay.Range.y0)
355 DoClearScreenBuffer();
359 ////////////////////////////////////////////////////////////////////////
360 // check if update needed
361 ////////////////////////////////////////////////////////////////////////
363 static void updateDisplayIfChanged(void) // UPDATE DISPLAY IF CHANGED
365 if ((PSXDisplay.DisplayMode.y == PSXDisplay.DisplayModeNew.y) &&
366 (PSXDisplay.DisplayMode.x == PSXDisplay.DisplayModeNew.x))
368 if((PSXDisplay.RGB24 == PSXDisplay.RGB24New) &&
369 (PSXDisplay.Interlaced == PSXDisplay.InterlacedNew)) return;
372 PSXDisplay.RGB24 = PSXDisplay.RGB24New; // get new infos
374 PSXDisplay.DisplayMode.y = PSXDisplay.DisplayModeNew.y;
375 PSXDisplay.DisplayMode.x = PSXDisplay.DisplayModeNew.x;
376 PreviousPSXDisplay.DisplayMode.x= // previous will hold
377 min(640,PSXDisplay.DisplayMode.x); // max 640x512... that's
378 PreviousPSXDisplay.DisplayMode.y= // the size of my
379 min(512,PSXDisplay.DisplayMode.y); // back buffer surface
380 PSXDisplay.Interlaced = PSXDisplay.InterlacedNew;
382 PSXDisplay.DisplayEnd.x= // calc end of display
383 PSXDisplay.DisplayPosition.x+ PSXDisplay.DisplayMode.x;
384 PSXDisplay.DisplayEnd.y=
385 PSXDisplay.DisplayPosition.y+ PSXDisplay.DisplayMode.y+PreviousPSXDisplay.DisplayModeNew.y;
386 PreviousPSXDisplay.DisplayEnd.x=
387 PreviousPSXDisplay.DisplayPosition.x+ PSXDisplay.DisplayMode.x;
388 PreviousPSXDisplay.DisplayEnd.y=
389 PreviousPSXDisplay.DisplayPosition.y+ PSXDisplay.DisplayMode.y+PreviousPSXDisplay.DisplayModeNew.y;
391 ChangeDispOffsetsX();
393 if(iFrameLimit==2) SetAutoFrameCap(); // -> set it
395 if(UseFrameSkip) decideSkip(); // stupid stuff when frame skipping enabled
398 ////////////////////////////////////////////////////////////////////////
399 // update lace is called evry VSync
400 ////////////////////////////////////////////////////////////////////////
402 void CALLBACK GPUupdateLace(void) // VSYNC
404 //if(!(dwActFixes&1))
405 // lGPUstatusRet^=0x80000000; // odd/even bit
407 //pcsx-rearmed: removed, this is handled by core
408 //if(!(dwActFixes&32)) // std fps limitation?
411 if(PSXDisplay.Interlaced) // interlaced mode?
413 lGPUstatusRet^=0x80000000; // odd/even bit?
415 if(bDoVSyncUpdate && PSXDisplay.DisplayMode.x>0 && PSXDisplay.DisplayMode.y>0)
420 else // non-interlaced?
422 if(dwActFixes&64) // lazy screen update fix
430 if(bDoVSyncUpdate) // some primitives drawn?
431 updateDisplay(); // -> update display
435 if(UseFrameSkip) { // frame over-skip guard
436 lace_count_since_flip++;
437 if(lace_count_since_flip > 8) {
438 bSkipNextFrame=FALSE;
439 fskip_frameReady=TRUE;
444 ////////////////////////////////////////////////////////////////////////
445 // process read request from GPU status register
446 ////////////////////////////////////////////////////////////////////////
449 uint32_t CALLBACK GPUreadStatus(void) // READ STATUS
453 static int iNumRead=0; // odd/even hack
457 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)
461 if(iFakePrimBusy) // 27.10.2007 - PETE : emulating some 'busy' while drawing... pfff
465 if(iFakePrimBusy&1) // we do a busy-idle-busy-idle sequence after/while drawing prims
468 GPUIsNotReadyForCommands;
473 GPUIsReadyForCommands;
476 return lGPUstatusRet | vBlank;
479 ////////////////////////////////////////////////////////////////////////
480 // processes data send to GPU status register
481 // these are always single packet commands.
482 ////////////////////////////////////////////////////////////////////////
484 void CALLBACK GPUwriteStatus(uint32_t gdata) // WRITE STATUS
486 uint32_t lCommand=(gdata>>24)&0xff;
488 ulStatusControl[lCommand]=gdata; // store command for freezing
492 //--------------------------------------------------//
495 memset(lGPUInfoVals,0x00,16*sizeof(uint32_t));
496 lGPUstatusRet=0x14802000;
497 PSXDisplay.Disabled=1;
498 DataWriteMode=DataReadMode=DR_NORMAL;
499 PSXDisplay.DrawOffset.x=PSXDisplay.DrawOffset.y=0;
500 drawX=drawY=0;drawW=drawH=0;
501 sSetMask=0;lSetMask=0;bCheckMask=FALSE;
503 GlobalTextAddrX=0;GlobalTextAddrY=0;
504 GlobalTextTP=0;GlobalTextABR=0;
505 PSXDisplay.RGB24=FALSE;
506 PSXDisplay.Interlaced=FALSE;
509 //--------------------------------------------------//
510 // dis/enable display
513 PreviousPSXDisplay.Disabled = PSXDisplay.Disabled;
514 PSXDisplay.Disabled = (gdata & 1);
516 if(PSXDisplay.Disabled)
517 lGPUstatusRet|=GPUSTATUS_DISPLAYDISABLED;
518 else lGPUstatusRet&=~GPUSTATUS_DISPLAYDISABLED;
521 //--------------------------------------------------//
522 // setting transfer mode
524 gdata &= 0x03; // Only want the lower two bits
526 DataWriteMode=DataReadMode=DR_NORMAL;
527 if(gdata==0x02) DataWriteMode=DR_VRAMTRANSFER;
528 if(gdata==0x03) DataReadMode =DR_VRAMTRANSFER;
529 lGPUstatusRet&=~GPUSTATUS_DMABITS; // Clear the current settings of the DMA bits
530 lGPUstatusRet|=(gdata << 29); // Set the DMA bits according to the received data
533 //--------------------------------------------------//
534 // setting display position
537 PreviousPSXDisplay.DisplayPosition.x = PSXDisplay.DisplayPosition.x;
538 PreviousPSXDisplay.DisplayPosition.y = PSXDisplay.DisplayPosition.y;
541 PSXDisplay.DisplayPosition.y = (short)((gdata>>10)&0x1ff);
543 // store the same val in some helper var, we need it on later compares
544 PreviousPSXDisplay.DisplayModeNew.x=PSXDisplay.DisplayPosition.y;
546 if((PSXDisplay.DisplayPosition.y+PSXDisplay.DisplayMode.y)>512)
548 int dy1=512-PSXDisplay.DisplayPosition.y;
549 int dy2=(PSXDisplay.DisplayPosition.y+PSXDisplay.DisplayMode.y)-512;
553 PreviousPSXDisplay.DisplayModeNew.y=-dy2;
557 PSXDisplay.DisplayPosition.y=0;
558 PreviousPSXDisplay.DisplayModeNew.y=-dy1;
561 else PreviousPSXDisplay.DisplayModeNew.y=0;
564 PSXDisplay.DisplayPosition.x = (short)(gdata & 0x3ff);
565 PSXDisplay.DisplayEnd.x=
566 PSXDisplay.DisplayPosition.x+ PSXDisplay.DisplayMode.x;
567 PSXDisplay.DisplayEnd.y=
568 PSXDisplay.DisplayPosition.y+ PSXDisplay.DisplayMode.y + PreviousPSXDisplay.DisplayModeNew.y;
569 PreviousPSXDisplay.DisplayEnd.x=
570 PreviousPSXDisplay.DisplayPosition.x+ PSXDisplay.DisplayMode.x;
571 PreviousPSXDisplay.DisplayEnd.y=
572 PreviousPSXDisplay.DisplayPosition.y+ PSXDisplay.DisplayMode.y + PreviousPSXDisplay.DisplayModeNew.y;
576 if (!(PSXDisplay.Interlaced)) // stupid frame skipping option
578 if(UseFrameSkip) decideSkip();
579 if(dwActFixes&64) bDoLazyUpdate=TRUE;
582 //--------------------------------------------------//
586 PSXDisplay.Range.x0=(short)(gdata & 0x7ff);
587 PSXDisplay.Range.x1=(short)((gdata>>12) & 0xfff);
589 PSXDisplay.Range.x1-=PSXDisplay.Range.x0;
591 ChangeDispOffsetsX();
594 //--------------------------------------------------//
599 PSXDisplay.Range.y0=(short)(gdata & 0x3ff);
600 PSXDisplay.Range.y1=(short)((gdata>>10) & 0x3ff);
602 PreviousPSXDisplay.Height = PSXDisplay.Height;
604 PSXDisplay.Height = PSXDisplay.Range.y1 -
605 PSXDisplay.Range.y0 +
606 PreviousPSXDisplay.DisplayModeNew.y;
608 if(PreviousPSXDisplay.Height!=PSXDisplay.Height)
610 PSXDisplay.DisplayModeNew.y=PSXDisplay.Height*PSXDisplay.Double;
612 ChangeDispOffsetsY();
614 updateDisplayIfChanged();
618 //--------------------------------------------------//
619 // setting display infos
622 PSXDisplay.DisplayModeNew.x =
623 sDispWidths[(gdata & 0x03) | ((gdata & 0x40) >> 4)];
625 if (gdata&0x04) PSXDisplay.Double=2;
626 else PSXDisplay.Double=1;
628 PSXDisplay.DisplayModeNew.y = PSXDisplay.Height*PSXDisplay.Double;
630 ChangeDispOffsetsY();
632 PSXDisplay.PAL = (gdata & 0x08)?TRUE:FALSE; // if 1 - PAL mode, else NTSC
633 PSXDisplay.RGB24New = (gdata & 0x10)?TRUE:FALSE; // if 1 - TrueColor
634 PSXDisplay.InterlacedNew = (gdata & 0x20)?TRUE:FALSE; // if 1 - Interlace
636 lGPUstatusRet&=~GPUSTATUS_WIDTHBITS; // Clear the width bits
638 (((gdata & 0x03) << 17) |
639 ((gdata & 0x40) << 10)); // Set the width bits
641 if(PSXDisplay.InterlacedNew)
643 if(!PSXDisplay.Interlaced)
645 PreviousPSXDisplay.DisplayPosition.x = PSXDisplay.DisplayPosition.x;
646 PreviousPSXDisplay.DisplayPosition.y = PSXDisplay.DisplayPosition.y;
648 lGPUstatusRet|=GPUSTATUS_INTERLACED;
650 else lGPUstatusRet&=~GPUSTATUS_INTERLACED;
653 lGPUstatusRet|=GPUSTATUS_PAL;
654 else lGPUstatusRet&=~GPUSTATUS_PAL;
656 if (PSXDisplay.Double==2)
657 lGPUstatusRet|=GPUSTATUS_DOUBLEHEIGHT;
658 else lGPUstatusRet&=~GPUSTATUS_DOUBLEHEIGHT;
660 if (PSXDisplay.RGB24New)
661 lGPUstatusRet|=GPUSTATUS_RGB24;
662 else lGPUstatusRet&=~GPUSTATUS_RGB24;
664 updateDisplayIfChanged();
667 //--------------------------------------------------//
668 // ask about GPU version and other stuff
676 lGPUdataRet=lGPUInfoVals[INFO_TW]; // tw infos
679 lGPUdataRet=lGPUInfoVals[INFO_DRAWSTART]; // draw start
682 lGPUdataRet=lGPUInfoVals[INFO_DRAWEND]; // draw end
686 lGPUdataRet=lGPUInfoVals[INFO_DRAWOFF]; // draw offset
689 lGPUdataRet=0x02; // gpu type
692 case 0x0F: // some bios addr?
693 lGPUdataRet=0xBFC03720;
697 //--------------------------------------------------//
701 ////////////////////////////////////////////////////////////////////////
702 // vram read/write helpers, needed by LEWPY's optimized vram read/write :)
703 ////////////////////////////////////////////////////////////////////////
705 static inline void FinishedVRAMWrite(void)
707 // Set register to NORMAL operation
708 DataWriteMode = DR_NORMAL;
709 // Reset transfer values, to prevent mis-transfer of data
713 VRAMWrite.Height = 0;
714 VRAMWrite.ColsRemaining = 0;
715 VRAMWrite.RowsRemaining = 0;
718 static inline void FinishedVRAMRead(void)
720 // Set register to NORMAL operation
721 DataReadMode = DR_NORMAL;
722 // Reset transfer values, to prevent mis-transfer of data
727 VRAMRead.ColsRemaining = 0;
728 VRAMRead.RowsRemaining = 0;
730 // Indicate GPU is no longer ready for VRAM data in the STATUS REGISTER
731 lGPUstatusRet&=~GPUSTATUS_READYFORVRAM;
734 ////////////////////////////////////////////////////////////////////////
735 // core read from vram
736 ////////////////////////////////////////////////////////////////////////
738 void CALLBACK GPUreadDataMem(uint32_t * pMem, int iSize)
742 if(DataReadMode!=DR_VRAMTRANSFER) return;
746 // adjust read ptr, if necessary
747 while(VRAMRead.ImagePtr>=psxVuw_eom)
748 VRAMRead.ImagePtr-=512*1024;
749 while(VRAMRead.ImagePtr<psxVuw)
750 VRAMRead.ImagePtr+=512*1024;
754 // do 2 seperate 16bit reads for compatibility (wrap issues)
755 if ((VRAMRead.ColsRemaining > 0) && (VRAMRead.RowsRemaining > 0))
758 lGPUdataRet=(uint32_t)GETLE16(VRAMRead.ImagePtr);
761 if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=512*1024;
762 VRAMRead.RowsRemaining --;
764 if(VRAMRead.RowsRemaining<=0)
766 VRAMRead.RowsRemaining = VRAMRead.Width;
767 VRAMRead.ColsRemaining--;
768 VRAMRead.ImagePtr += 1024 - VRAMRead.Width;
769 if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=512*1024;
772 // higher 16 bit (always, even if it's an odd width)
773 lGPUdataRet|=(uint32_t)GETLE16(VRAMRead.ImagePtr)<<16;
774 PUTLE32(pMem, lGPUdataRet); pMem++;
776 if(VRAMRead.ColsRemaining <= 0)
777 {FinishedVRAMRead();goto ENDREAD;}
780 if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=512*1024;
781 VRAMRead.RowsRemaining--;
782 if(VRAMRead.RowsRemaining<=0)
784 VRAMRead.RowsRemaining = VRAMRead.Width;
785 VRAMRead.ColsRemaining--;
786 VRAMRead.ImagePtr += 1024 - VRAMRead.Width;
787 if(VRAMRead.ImagePtr>=psxVuw_eom) VRAMRead.ImagePtr-=512*1024;
789 if(VRAMRead.ColsRemaining <= 0)
790 {FinishedVRAMRead();goto ENDREAD;}
792 else {FinishedVRAMRead();goto ENDREAD;}
800 ////////////////////////////////////////////////////////////////////////
802 uint32_t CALLBACK GPUreadData(void)
805 GPUreadDataMem(&l,1);
809 // Software drawing function
812 // PSX drawing primitives
815 ////////////////////////////////////////////////////////////////////////
816 // processes data send to GPU data register
817 // extra table entries for fixing polyline troubles
818 ////////////////////////////////////////////////////////////////////////
820 static const unsigned char primTableCX[256] =
841 // 5,5,5,5,6,6,6,6, // FLINE
842 254,254,254,254,254,254,254,254,
846 // 7,7,7,7,9,9,9,9, // GLINE
847 255,255,255,255,255,255,255,255,
851 2,2,2,2,3,3,3,3, // 3=SPRITE1???
890 void CALLBACK GPUwriteDataMem(uint32_t * pMem, int iSize)
892 unsigned char command;
896 GPUIsNotReadyForCommands;
900 if(DataWriteMode==DR_VRAMTRANSFER)
902 BOOL bFinished=FALSE;
904 // make sure we are in vram
905 while(VRAMWrite.ImagePtr>=psxVuw_eom)
906 VRAMWrite.ImagePtr-=512*1024;
907 while(VRAMWrite.ImagePtr<psxVuw)
908 VRAMWrite.ImagePtr+=512*1024;
911 while(VRAMWrite.ColsRemaining>0)
913 while(VRAMWrite.RowsRemaining>0)
915 if(i>=iSize) {goto ENDVRAM;}
918 gdata=GETLE32(pMem); pMem++;
920 PUTLE16(VRAMWrite.ImagePtr, (unsigned short)gdata); VRAMWrite.ImagePtr++;
921 if(VRAMWrite.ImagePtr>=psxVuw_eom) VRAMWrite.ImagePtr-=512*1024;
922 VRAMWrite.RowsRemaining --;
924 if(VRAMWrite.RowsRemaining <= 0)
926 VRAMWrite.ColsRemaining--;
927 if (VRAMWrite.ColsRemaining <= 0) // last pixel is odd width
929 gdata=(gdata&0xFFFF)|(((uint32_t)GETLE16(VRAMWrite.ImagePtr))<<16);
934 VRAMWrite.RowsRemaining = VRAMWrite.Width;
935 VRAMWrite.ImagePtr += 1024 - VRAMWrite.Width;
938 PUTLE16(VRAMWrite.ImagePtr, (unsigned short)(gdata>>16)); VRAMWrite.ImagePtr++;
939 if(VRAMWrite.ImagePtr>=psxVuw_eom) VRAMWrite.ImagePtr-=512*1024;
940 VRAMWrite.RowsRemaining --;
943 VRAMWrite.RowsRemaining = VRAMWrite.Width;
944 VRAMWrite.ColsRemaining--;
945 VRAMWrite.ImagePtr += 1024 - VRAMWrite.Width;
950 if(bFinished) bDoVSyncUpdate=TRUE;
955 if(DataWriteMode==DR_NORMAL)
957 void (* *primFunc)(unsigned char *);
958 if(bSkipNextFrame) primFunc=primTableSkip;
959 else primFunc=primTableJ;
963 if(DataWriteMode==DR_VRAMTRANSFER) goto STARTVRAM;
965 gdata=GETLE32(pMem); pMem++; i++;
969 command = (unsigned char)((gdata>>24) & 0xff);
971 //if(command>=0xb0 && command<0xc0) auxprintf("b0 %x!!!!!!!!!\n",command);
973 if(primTableCX[command])
975 gpuDataC = primTableCX[command];
976 gpuCommand = command;
977 PUTLE32_(&gpuDataM[0], gdata);
984 PUTLE32_(&gpuDataM[gpuDataP], gdata);
987 if((gpuDataC==254 && gpuDataP>=3) ||
988 (gpuDataC==255 && gpuDataP>=4 && !(gpuDataP&1)))
990 if((gpuDataM[gpuDataP] & 0xF000F000) == 0x50005000)
997 if(gpuDataP == gpuDataC)
1000 primFunc[gpuCommand]((unsigned char *)gpuDataM);
1001 if(dwActFixes&0x0400) // hack for emulating "gpu busy" in some games
1009 GPUIsReadyForCommands;
1013 ////////////////////////////////////////////////////////////////////////
1015 void CALLBACK GPUwriteData(uint32_t gdata)
1017 PUTLE32_(&gdata, gdata);
1018 GPUwriteDataMem(&gdata,1);
1021 ////////////////////////////////////////////////////////////////////////
1022 // process gpu commands
1023 ////////////////////////////////////////////////////////////////////////
1025 unsigned long lUsedAddr[3];
1027 static inline BOOL CheckForEndlessLoop(unsigned long laddr)
1029 if(laddr==lUsedAddr[1]) return TRUE;
1030 if(laddr==lUsedAddr[2]) return TRUE;
1032 if(laddr<lUsedAddr[0]) lUsedAddr[1]=laddr;
1033 else lUsedAddr[2]=laddr;
1038 long CALLBACK GPUdmaChain(uint32_t * baseAddrL, uint32_t addr)
1041 unsigned char * baseAddrB;
1042 short count;unsigned int DMACommandCounter = 0;
1046 lUsedAddr[0]=lUsedAddr[1]=lUsedAddr[2]=0xffffff;
1048 baseAddrB = (unsigned char*) baseAddrL;
1053 if(DMACommandCounter++ > 2000000) break;
1054 if(CheckForEndlessLoop(addr)) break;
1056 count = baseAddrB[addr+3];
1060 if(count>0) GPUwriteDataMem(&baseAddrL[dmaMem>>2],count);
1062 addr = GETLE32(&baseAddrL[addr>>2])&0xffffff;
1064 while (addr != 0xffffff);
1071 ////////////////////////////////////////////////////////////////////////
1073 ////////////////////////////////////////////////////////////////////////
1075 typedef struct GPUFREEZETAG
1077 uint32_t ulFreezeVersion; // should be always 1 for now (set by main emu)
1078 uint32_t ulStatus; // current gpu status
1079 uint32_t ulControl[256]; // latest control register values
1080 unsigned char psxVRam[1024*1024*2]; // current VRam image (full 2 MB for ZN)
1083 ////////////////////////////////////////////////////////////////////////
1085 long CALLBACK GPUfreeze(uint32_t ulGetFreezeData,GPUFreeze_t * pF)
1087 //----------------------------------------------------//
1088 if(ulGetFreezeData==2) // 2: info, which save slot is selected? (just for display)
1090 long lSlotNum=*((long *)pF);
1091 if(lSlotNum<0) return 0;
1092 if(lSlotNum>8) return 0;
1093 lSelectedSlot=lSlotNum+1;
1096 //----------------------------------------------------//
1097 if(!pF) return 0; // some checks
1098 if(pF->ulFreezeVersion!=1) return 0;
1100 if(ulGetFreezeData==1) // 1: get data
1102 pF->ulStatus=lGPUstatusRet;
1103 memcpy(pF->ulControl,ulStatusControl,256*sizeof(uint32_t));
1104 memcpy(pF->psxVRam, psxVub, 1024*512*2);
1109 if(ulGetFreezeData!=0) return 0; // 0: set data
1111 lGPUstatusRet=pF->ulStatus;
1112 memcpy(ulStatusControl,pF->ulControl,256*sizeof(uint32_t));
1113 memcpy(psxVub, pF->psxVRam, 1024*512*2);
1115 // RESET TEXTURE STORE HERE, IF YOU USE SOMETHING LIKE THAT
1117 GPUwriteStatus(ulStatusControl[0]);
1118 GPUwriteStatus(ulStatusControl[1]);
1119 GPUwriteStatus(ulStatusControl[2]);
1120 GPUwriteStatus(ulStatusControl[3]);
1121 GPUwriteStatus(ulStatusControl[8]); // try to repair things
1122 GPUwriteStatus(ulStatusControl[6]);
1123 GPUwriteStatus(ulStatusControl[7]);
1124 GPUwriteStatus(ulStatusControl[5]);
1125 GPUwriteStatus(ulStatusControl[4]);
1130 void CALLBACK GPUvBlank(int val)
1132 vBlank=val?0x80000000:0;