2010-09-13 08:43:32 +02:00
|
|
|
/* Copyright (c) 2010, shalma.
|
|
|
|
* Portions Copyright (c) 2002, Pete Bernert.
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
2012-02-19 03:15:18 +01:00
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
2010-09-13 08:43:32 +02:00
|
|
|
*/
|
|
|
|
|
2010-09-05 03:11:09 +02:00
|
|
|
#include "psxhw.h"
|
|
|
|
#include "gpu.h"
|
|
|
|
#include "psxdma.h"
|
|
|
|
|
|
|
|
#define GPUSTATUS_ODDLINES 0x80000000
|
|
|
|
#define GPUSTATUS_DMABITS 0x60000000 // Two bits
|
|
|
|
#define GPUSTATUS_READYFORCOMMANDS 0x10000000
|
|
|
|
#define GPUSTATUS_READYFORVRAM 0x08000000
|
|
|
|
#define GPUSTATUS_IDLE 0x04000000
|
|
|
|
|
|
|
|
#define GPUSTATUS_DISPLAYDISABLED 0x00800000
|
|
|
|
#define GPUSTATUS_INTERLACED 0x00400000
|
|
|
|
#define GPUSTATUS_RGB24 0x00200000
|
|
|
|
#define GPUSTATUS_PAL 0x00100000
|
|
|
|
#define GPUSTATUS_DOUBLEHEIGHT 0x00080000
|
|
|
|
#define GPUSTATUS_WIDTHBITS 0x00070000 // Three bits
|
|
|
|
#define GPUSTATUS_MASKENABLED 0x00001000
|
|
|
|
#define GPUSTATUS_MASKDRAWN 0x00000800
|
|
|
|
#define GPUSTATUS_DRAWINGALLOWED 0x00000400
|
|
|
|
#define GPUSTATUS_DITHER 0x00000200
|
|
|
|
|
|
|
|
// Taken from PEOPS SOFTGPU
|
2010-09-13 08:43:32 +02:00
|
|
|
u32 lUsedAddr[3];
|
2010-09-05 03:11:09 +02:00
|
|
|
|
2010-09-13 09:01:43 +02:00
|
|
|
static inline boolean CheckForEndlessLoop(u32 laddr) {
|
2010-09-13 08:43:32 +02:00
|
|
|
if (laddr == lUsedAddr[1]) return TRUE;
|
|
|
|
if (laddr == lUsedAddr[2]) return TRUE;
|
2010-09-05 03:11:09 +02:00
|
|
|
|
2010-09-13 08:43:32 +02:00
|
|
|
if (laddr < lUsedAddr[0]) lUsedAddr[1] = laddr;
|
|
|
|
else lUsedAddr[2] = laddr;
|
2010-09-05 03:11:09 +02:00
|
|
|
|
2010-09-13 08:43:32 +02:00
|
|
|
lUsedAddr[0] = laddr;
|
2010-09-05 03:11:09 +02:00
|
|
|
|
2010-09-13 08:43:32 +02:00
|
|
|
return FALSE;
|
|
|
|
}
|
2010-09-05 03:11:09 +02:00
|
|
|
|
2010-09-13 09:01:43 +02:00
|
|
|
static u32 gpuDmaChainSize(u32 addr) {
|
2010-09-16 02:48:29 +02:00
|
|
|
u32 size;
|
|
|
|
u32 DMACommandCounter = 0;
|
2010-09-05 03:11:09 +02:00
|
|
|
|
2010-09-13 08:43:32 +02:00
|
|
|
lUsedAddr[0] = lUsedAddr[1] = lUsedAddr[2] = 0xffffff;
|
2010-09-05 03:11:09 +02:00
|
|
|
|
2010-11-08 03:09:55 +01:00
|
|
|
// initial linked list ptr (word)
|
|
|
|
size = 1;
|
2010-09-16 02:48:29 +02:00
|
|
|
|
2010-09-13 08:43:32 +02:00
|
|
|
do {
|
|
|
|
addr &= 0x1ffffc;
|
2010-09-05 03:11:09 +02:00
|
|
|
|
2010-11-13 20:02:15 +01:00
|
|
|
if (DMACommandCounter++ > 2000000) break;
|
|
|
|
if (CheckForEndlessLoop(addr)) break;
|
2010-09-05 03:11:09 +02:00
|
|
|
|
2010-11-12 03:31:37 +01:00
|
|
|
|
2010-09-16 02:48:29 +02:00
|
|
|
// # 32-bit blocks to transfer
|
2010-11-08 03:09:55 +01:00
|
|
|
size += psxMu8( addr + 3 );
|
2010-09-05 03:11:09 +02:00
|
|
|
|
2011-03-11 21:08:35 +01:00
|
|
|
|
2010-09-16 02:48:29 +02:00
|
|
|
// next 32-bit pointer
|
|
|
|
addr = psxMu32( addr & ~0x3 ) & 0xffffff;
|
2010-11-08 03:09:55 +01:00
|
|
|
size += 1;
|
2010-09-13 08:43:32 +02:00
|
|
|
} while (addr != 0xffffff);
|
2010-09-05 03:11:09 +02:00
|
|
|
|
2011-03-11 21:08:35 +01:00
|
|
|
|
2010-09-13 08:43:32 +02:00
|
|
|
return size;
|
2010-09-05 03:11:09 +02:00
|
|
|
}
|
|
|
|
|
2010-09-13 08:43:32 +02:00
|
|
|
int gpuReadStatus() {
|
2010-09-05 03:11:09 +02:00
|
|
|
int hard;
|
|
|
|
|
|
|
|
|
|
|
|
// GPU plugin
|
|
|
|
hard = GPU_readStatus();
|
|
|
|
|
|
|
|
|
|
|
|
// Gameshark Lite - wants to see VRAM busy
|
|
|
|
// - Must enable GPU 'Fake Busy States' hack
|
|
|
|
if( (hard & GPUSTATUS_IDLE) == 0 )
|
|
|
|
hard &= ~GPUSTATUS_READYFORVRAM;
|
|
|
|
|
|
|
|
return hard;
|
|
|
|
}
|
|
|
|
|
|
|
|
void psxDma2(u32 madr, u32 bcr, u32 chcr) { // GPU
|
|
|
|
u32 *ptr;
|
|
|
|
u32 size;
|
|
|
|
|
2010-09-13 08:43:32 +02:00
|
|
|
switch (chcr) {
|
2010-09-05 03:11:09 +02:00
|
|
|
case 0x01000200: // vram2mem
|
|
|
|
#ifdef PSXDMA_LOG
|
|
|
|
PSXDMA_LOG("*** DMA2 GPU - vram2mem *** %lx addr = %lx size = %lx\n", chcr, madr, bcr);
|
|
|
|
#endif
|
|
|
|
ptr = (u32 *)PSXM(madr);
|
|
|
|
if (ptr == NULL) {
|
|
|
|
#ifdef CPU_LOG
|
|
|
|
CPU_LOG("*** DMA2 GPU - vram2mem *** NULL Pointer!!!\n");
|
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
}
|
2010-09-16 02:48:29 +02:00
|
|
|
// BA blocks * BS words (word = 32-bits)
|
2010-09-05 03:11:09 +02:00
|
|
|
size = (bcr >> 16) * (bcr & 0xffff);
|
|
|
|
GPU_readDataMem(ptr, size);
|
|
|
|
psxCpu->Clear(madr, size);
|
|
|
|
|
2011-02-02 04:10:33 +01:00
|
|
|
#if 1
|
2010-09-16 02:48:29 +02:00
|
|
|
// already 32-bit word size ((size * 4) / 4)
|
|
|
|
GPUDMA_INT(size);
|
2011-02-02 04:10:33 +01:00
|
|
|
#else
|
2011-02-02 18:26:59 +01:00
|
|
|
// Experimental burst dma transfer (0.333x max)
|
2011-02-02 15:42:02 +01:00
|
|
|
GPUDMA_INT(size/3);
|
2011-02-02 04:10:33 +01:00
|
|
|
#endif
|
2010-09-05 03:11:09 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
case 0x01000201: // mem2vram
|
|
|
|
#ifdef PSXDMA_LOG
|
|
|
|
PSXDMA_LOG("*** DMA 2 - GPU mem2vram *** %lx addr = %lx size = %lx\n", chcr, madr, bcr);
|
|
|
|
#endif
|
|
|
|
ptr = (u32 *)PSXM(madr);
|
|
|
|
if (ptr == NULL) {
|
|
|
|
#ifdef CPU_LOG
|
|
|
|
CPU_LOG("*** DMA2 GPU - mem2vram *** NULL Pointer!!!\n");
|
|
|
|
#endif
|
|
|
|
break;
|
|
|
|
}
|
2010-09-16 02:48:29 +02:00
|
|
|
// BA blocks * BS words (word = 32-bits)
|
2010-09-05 03:11:09 +02:00
|
|
|
size = (bcr >> 16) * (bcr & 0xffff);
|
|
|
|
GPU_writeDataMem(ptr, size);
|
|
|
|
|
2011-02-02 04:10:33 +01:00
|
|
|
#if 1
|
2010-09-16 02:48:29 +02:00
|
|
|
// already 32-bit word size ((size * 4) / 4)
|
|
|
|
GPUDMA_INT(size);
|
2011-02-02 04:10:33 +01:00
|
|
|
#else
|
2011-02-02 18:26:59 +01:00
|
|
|
// Experimental burst dma transfer
|
2011-02-02 15:42:02 +01:00
|
|
|
// - X-Files = 0.333333x max for videos
|
|
|
|
GPUDMA_INT( size / 3 );
|
2011-02-02 04:10:33 +01:00
|
|
|
#endif
|
2010-09-05 03:11:09 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
case 0x01000401: // dma chain
|
|
|
|
#ifdef PSXDMA_LOG
|
|
|
|
PSXDMA_LOG("*** DMA 2 - GPU dma chain *** %lx addr = %lx size = %lx\n", chcr, madr, bcr);
|
|
|
|
#endif
|
|
|
|
|
2010-11-12 03:31:37 +01:00
|
|
|
size = gpuDmaChainSize(madr);
|
|
|
|
GPU_dmaChain((u32 *)psxM, madr & 0x1fffff);
|
2011-03-11 21:08:35 +01:00
|
|
|
|
2010-11-28 01:30:45 +01:00
|
|
|
// Tekken 3 = use 1.0 only (not 1.5x)
|
|
|
|
|
|
|
|
// Einhander = parse linked list in pieces (todo)
|
|
|
|
// Final Fantasy 4 = internal vram time (todo)
|
|
|
|
// Rebel Assault 2 = parse linked list in pieces (todo)
|
|
|
|
// Vampire Hunter D = allow edits to linked list (todo)
|
|
|
|
GPUDMA_INT(size);
|
2010-09-05 03:11:09 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
#ifdef PSXDMA_LOG
|
|
|
|
default:
|
|
|
|
PSXDMA_LOG("*** DMA 2 - GPU unknown *** %lx addr = %lx size = %lx\n", chcr, madr, bcr);
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
HW_DMA2_CHCR &= SWAP32(~0x01000000);
|
|
|
|
DMA_INTERRUPT(2);
|
|
|
|
}
|
|
|
|
|
|
|
|
void gpuInterrupt() {
|
|
|
|
HW_DMA2_CHCR &= SWAP32(~0x01000000);
|
|
|
|
DMA_INTERRUPT(2);
|
|
|
|
}
|