Play-/Source/GSHandler.h
jpd002 7045812409 Fixed PSMT4 transfers.
git-svn-id: http://svn.purei.org/purei/trunk@369 b36208d7-6611-0410-8bec-b1987f11c4a2
2008-10-03 00:32:26 +00:00

724 lines
19 KiB
C++

#ifndef _GS_H_
#define _GS_H_
#include "Types.h"
#include "Convertible.h"
#include <boost/thread.hpp>
#include <boost/signal.hpp>
#include <boost/static_assert.hpp>
#include <vector>
#include <functional>
#include "MailBox.h"
#include "zip/ZipArchiveWriter.h"
#include "zip/ZipArchiveReader.h"
#pragma pack(push, 1)
enum GS_REGS
{
GS_REG_PRIM = 0x00,
GS_REG_RGBAQ = 0x01,
GS_REG_ST = 0x02,
GS_REG_UV = 0x03,
GS_REG_XYZF2 = 0x04,
GS_REG_XYZ2 = 0x05,
GS_REG_TEX0_1 = 0x06,
GS_REG_TEX0_2 = 0x07,
GS_REG_CLAMP_1 = 0x08,
GS_REG_CLAMP_2 = 0x09,
GS_REG_FOG = 0x0A,
GS_REG_XYZF3 = 0x0C,
GS_REG_XYZ3 = 0x0D,
GS_REG_TEX1_1 = 0x14,
GS_REG_TEX1_2 = 0x15,
GS_REG_TEX2_1 = 0x16,
GS_REG_TEX2_2 = 0x17,
GS_REG_XYOFFSET_1 = 0x18,
GS_REG_XYOFFSET_2 = 0x19,
GS_REG_PRMODECONT = 0x1A,
GS_REG_PRMODE = 0x1B,
GS_REG_TEXCLUT = 0x1C,
GS_REG_TEXA = 0x3B,
GS_REG_FOGCOL = 0x3D,
GS_REG_TEXFLUSH = 0x3F,
GS_REG_SCISSOR_1 = 0x40,
GS_REG_ALPHA_1 = 0x42,
GS_REG_ALPHA_2 = 0x43,
GS_REG_TEST_1 = 0x47,
GS_REG_TEST_2 = 0x48,
GS_REG_FRAME_1 = 0x4C,
GS_REG_FRAME_2 = 0x4D,
GS_REG_ZBUF_1 = 0x4E,
GS_REG_ZBUF_2 = 0x4F,
GS_REG_BITBLTBUF = 0x50,
GS_REG_TRXPOS = 0x51,
GS_REG_TRXREG = 0x52,
GS_REG_TRXDIR = 0x53,
};
struct GSTEX0
{
unsigned int nBufPtr : 14;
unsigned int nBufWidth : 6;
unsigned int nPsm : 6;
unsigned int nWidth : 4;
unsigned int nPad0 : 2;
unsigned int nPad1 : 2;
unsigned int nColorComp : 1;
unsigned int nFunction : 2;
unsigned int nCBP : 14;
unsigned int nCPSM : 4;
unsigned int nCSM : 1;
unsigned int nCSA : 5;
unsigned int nCLD : 3;
uint32 GetBufPtr() { return nBufPtr * 256; }
uint32 GetBufWidth() { return nBufWidth * 64; }
uint32 GetWidth() { return (1 << nWidth); }
uint32 GetHeight() { return (1 << (nPad0 | (nPad1 << 2))); }
uint32 GetCLUTPtr() { return nCBP * 256; }
};
struct GSTEX1
{
unsigned int nLODMethod : 1;
unsigned int nReserved0 : 1;
unsigned int nMaxMip : 3;
unsigned int nMagFilter : 1;
unsigned int nMinFilter : 3;
unsigned int nMipBaseAddr : 1;
unsigned int nReserved1 : 9;
unsigned int nLODL : 2;
unsigned int nReserved2 : 11;
unsigned int nLODK : 7;
unsigned int nReserved3 : 25;
};
struct GSRGBAQ
{
uint8 nR;
uint8 nG;
uint8 nB;
uint8 nA;
float nQ;
};
struct GSDISPLAY
{
unsigned int nX : 12;
unsigned int nY : 11;
unsigned int nMagX : 4;
unsigned int nMagY : 5;
unsigned int nW : 12;
unsigned int nH : 12;
};
struct GSPRIM
{
unsigned int nType : 3;
unsigned int nShading : 1;
unsigned int nTexture : 1;
unsigned int nFog : 1;
unsigned int nAlpha : 1;
unsigned int nAntiAliasing : 1;
unsigned int nUseUV : 1;
unsigned int nContext : 1;
unsigned int nUseFloat : 1;
};
struct GSPRMODE
{
unsigned int nReserved0 : 3;
unsigned int nShading : 1;
unsigned int nTexture : 1;
unsigned int nFog : 1;
unsigned int nAlpha : 1;
unsigned int nAntiAliasing : 1;
unsigned int nUseUV : 1;
unsigned int nContext : 1;
unsigned int nUseFloat : 1;
};
struct GSTEXA
{
unsigned int nTA0 : 8;
unsigned int nReserved0 : 7;
unsigned int nAEM : 1;
unsigned int nReserved1 : 16;
unsigned int nTA1 : 8;
unsigned int nReserved2 : 24;
};
struct GSALPHA
{
unsigned int nA : 2;
unsigned int nB : 2;
unsigned int nC : 2;
unsigned int nD : 2;
unsigned int nReserved0 : 24;
unsigned int nFix : 8;
unsigned int nReserved1 : 24;
};
#pragma pack(pop)
#define DECODE_DISPLAY(v, d) \
(d) = *(GSDISPLAY*)&(v);
#define DECODE_PRIM(v, pr) \
(pr) = *(GSPRIM*)&(v);
#define DECODE_PRMODE(v, prm) \
(prm) = *(GSPRMODE*)&(v);
#define DECODE_TEXA(v, texa) \
(texa) = *(GSTEXA*)&(v);
#define DECODE_TEX0(v, tex) \
(tex) = *(GSTEX0*)&(v);
#define DECODE_TEX1(v, tex) \
(tex) = *(GSTEX1*)&(v);
#define DECODE_RGBAQ(v, rgbaq) \
(rgbaq) = *(GSRGBAQ*)&(v);
#define DECODE_UV(p, u, v) \
(u) = (double)((p >> 4) & 0xFFF); \
(u) += (double)((p >> 0) & 0xF) / 16.0f; \
(v) = (double)((p >> 20) & 0xFFF); \
(v) += (double)((p >> 16) & 0xF) / 16.0f;
#define DECODE_ST(p, s, t) \
(s) = *(float*)((uint32*)&(p) + 0); \
(t) = *(float*)((uint32*)&(p) + 1);
#define DECODE_XYZ2(v, x, y, z) \
(x) = (double)(((v >> 0) & 0xFFFF)) / 16.0; \
(y) = (double)(((v >> 16) & 0xFFFF)) / 16.0; \
(z) = (double)((v >> 32) & 0xFFFFFFFF);
#define DECODE_XYOFFSET(v, x, y) \
(x) = (double)((v >> 0) & 0xFFFF) / 16.0; \
(y) = (double)((v >> 32) & 0xFFFF) / 16.0; \
#define DECODE_ALPHA(v, alpha) \
(alpha) = *(GSALPHA*)&(v);
class CGSHandler
{
public:
typedef std::pair<uint8, uint64> RegisterWrite;
typedef std::vector<RegisterWrite> RegisterWriteList;
typedef std::tr1::function<CGSHandler* (void)> FactoryFunction;
CGSHandler();
virtual ~CGSHandler();
void Reset();
void SetEnabled(bool);
virtual void SaveState(CZipArchiveWriter&);
virtual void LoadState(CZipArchiveReader&);
virtual void WritePrivRegister(uint32, uint32);
virtual uint32 ReadPrivRegister(uint32);
void DisassembleWrite(uint8, uint64);
virtual void SetVBlank();
void ResetVBlank();
void WriteRegister(uint8, uint64);
void FeedImageData(void*, uint32);
void WriteRegisterMassively(const RegisterWrite*, unsigned int);
void FetchImagePSMCT16(uint16*, uint32, uint32, uint32, uint32);
void FetchImagePSMCT16S(uint16*, uint32, uint32, uint32, uint32);
void FetchImagePSMCT32(uint32*, uint32, uint32, uint32, uint32);
virtual void SetCrt(bool, unsigned int, bool);
void Initialize();
void UpdateViewport();
virtual void ProcessImageTransfer(uint32, uint32) = 0;
void Flip();
boost::signal<void ()> OnNewFrame;
enum PRIVATE_REGISTER
{
GS_CSR = 0x12001000,
GS_IMR = 0x12001010,
};
protected:
enum RAMSIZE
{
RAMSIZE = 0x00400000,
};
enum PSM
{
PSMCT32 = 0x00,
PSMCT24 = 0x01,
PSMCT16 = 0x02,
PSMCT16S = 0x0A,
PSMT8 = 0x13,
PSMT4 = 0x14,
PSMT8H = 0x1B,
PSMT4HL = 0x24,
PSMT4HH = 0x2C,
PSMZ32 = 0x30,
PSMZ24 = 0x31,
PSMZ16 = 0x32,
PSMZ16S = 0x3A,
PSM_MAX,
};
struct DISPFB
{
unsigned int nBufPtr : 9;
unsigned int nBufWidth : 6;
unsigned int nPSM : 5;
unsigned int nReserved0 : 12;
unsigned int nX : 11;
unsigned int nY : 11;
unsigned int nReserved1 : 10;
uint32 GetBufPtr() { return nBufPtr * 8192; };
uint32 GetBufWidth() { return nBufWidth * 64; };
};
//Reg 0x04/0x0C
struct XYZF
{
unsigned int nX : 16;
unsigned int nY : 16;
unsigned int nZ : 24;
unsigned int nF : 8;
double GetX() { return (double)nX / 16.0; }
double GetY() { return (double)nY / 16.0; }
};
//Reg 0x08/0x09
struct CLAMP
{
unsigned int nWMS : 2;
unsigned int nWMT : 2;
unsigned int nMINU : 10;
unsigned int nMAXU : 10;
unsigned int nReserved0 : 8;
unsigned int nReserved1 : 2;
unsigned int nMAXV : 10;
unsigned int nReserved2 : 22;
unsigned int GetMinU() { return nMINU; }
unsigned int GetMaxU() { return nMAXU; }
unsigned int GetMinV() { return (nReserved0) | (nReserved1 << 8); }
unsigned int GetMaxV() { return nMAXV; }
};
//Reg 0x16/0x17
struct TEX2
{
unsigned int nReserved0 : 20;
unsigned int nPsm : 6;
unsigned int nReserved1 : 6;
unsigned int nReserved2 : 5;
unsigned int nCBP : 14;
unsigned int nCPSM : 4;
unsigned int nCSM : 1;
unsigned int nCSA : 5;
unsigned int nCLD : 3;
uint32 GetCLUTPtr() { return nCBP * 256; }
};
//Reg 0x3D
struct FOGCOL
{
unsigned int nFCR : 8;
unsigned int nFCG : 8;
unsigned int nFCB : 8;
unsigned int nReserved0 : 8;
unsigned int nReserved1 : 32;
};
//Reg 0x3F
struct TEXCLUT
{
unsigned int nCBW : 6;
unsigned int nCOU : 6;
unsigned int nCOV : 10;
unsigned int nReserved1 : 10;
unsigned int nReserved2 : 32;
uint32 GetBufWidth() { return nCBW * 64; }
uint32 GetOffsetU() { return nCOU * 16; }
uint32 GetOffsetV() { return nCOV; }
};
//Reg 0x47/0x48
struct TEST : public convertible<uint64>
{
unsigned int nAlphaEnabled : 1;
unsigned int nAlphaMethod : 3;
unsigned int nAlphaRef : 8;
unsigned int nAlphaFail : 2;
unsigned int nDestAlphaEnabled : 1;
unsigned int nDestAlphaMode : 1;
unsigned int nDepthEnabled : 1;
unsigned int nDepthMethod : 2;
unsigned int nReserved0 : 13;
uint32 nReserved1;
};
BOOST_STATIC_ASSERT(sizeof(TEST) == sizeof(uint64));
//Reg 0x4C/0x4D
struct FRAME
{
unsigned int nPtr : 16;
unsigned int nWidth : 8;
unsigned int nPsm : 8;
unsigned int nMask : 32;
uint32 GetBasePtr() { return nPtr * 8192; }
uint32 GetWidth() { return nWidth * 64; }
};
//Reg 0x4E/0x4F
struct ZBUF
{
unsigned int nPtr : 9;
unsigned int nReserved0 : 15;
unsigned int nPsm : 4;
unsigned int nReserved1 : 4;
unsigned int nMask : 1;
uint32 GetBasePtr() { return nPtr * 2048; }
};
//Reg 0x50
struct BITBLTBUF
{
unsigned int nSrcPtr : 14;
unsigned int nReserved0 : 2;
unsigned int nSrcWidth : 6;
unsigned int nReserved1 : 2;
unsigned int nSrcPsm : 6;
unsigned int nReserved2 : 2;
unsigned int nDstPtr : 14;
unsigned int nReserved3 : 2;
unsigned int nDstWidth : 6;
unsigned int nReserved4 : 2;
unsigned int nDstPsm : 6;
unsigned int nReserved5 : 2;
uint32 GetSrcPtr() { return nSrcPtr * 256; }
uint32 GetSrcWidth() { return nSrcWidth * 64; }
uint32 GetDstPtr() { return nDstPtr * 256; }
uint32 GetDstWidth() { return nDstWidth * 64; }
};
//Reg 0x51
struct TRXPOS
{
unsigned int nSSAX : 11;
unsigned int nReserved0 : 5;
unsigned int nSSAY : 11;
unsigned int nReserved1 : 5;
unsigned int nDSAX : 11;
unsigned int nReserved2 : 5;
unsigned int nDSAY : 11;
unsigned int nDIR : 2;
unsigned int nReserved3 : 3;
};
//Reg 0x52
struct TRXREG
{
unsigned int nRRW : 12;
unsigned int nReserved0 : 20;
unsigned int nRRH : 12;
unsigned int nReserved1 : 20;
};
struct TRXCONTEXT
{
uint32 nSize;
uint32 nRRX;
uint32 nRRY;
bool nDirty;
};
struct STORAGEPSMCT32
{
enum PAGEWIDTH { PAGEWIDTH = 64 };
enum PAGEHEIGHT { PAGEHEIGHT = 32 };
enum BLOCKWIDTH { BLOCKWIDTH = 8 };
enum BLOCKHEIGHT { BLOCKHEIGHT = 8 };
enum COLUMNWIDTH { COLUMNWIDTH = 8 };
enum COLUMNHEIGHT { COLUMNHEIGHT = 2 };
static int m_nBlockSwizzleTable[4][8];
static int m_nColumnSwizzleTable[2][8];
typedef uint32 Unit;
};
struct STORAGEPSMCT16
{
enum PAGEWIDTH { PAGEWIDTH = 64 };
enum PAGEHEIGHT { PAGEHEIGHT = 64 };
enum BLOCKWIDTH { BLOCKWIDTH = 16 };
enum BLOCKHEIGHT { BLOCKHEIGHT = 8 };
enum COLUMNWIDTH { COLUMNWIDTH = 16 };
enum COLUMNHEIGHT { COLUMNHEIGHT = 2 };
static int m_nBlockSwizzleTable[8][4];
static int m_nColumnSwizzleTable[2][16];
typedef uint16 Unit;
};
struct STORAGEPSMCT16S
{
enum PAGEWIDTH { PAGEWIDTH = 64 };
enum PAGEHEIGHT { PAGEHEIGHT = 64 };
enum BLOCKWIDTH { BLOCKWIDTH = 16 };
enum BLOCKHEIGHT { BLOCKHEIGHT = 8 };
enum COLUMNWIDTH { COLUMNWIDTH = 16 };
enum COLUMNHEIGHT { COLUMNHEIGHT = 2 };
static int m_nBlockSwizzleTable[8][4];
static int m_nColumnSwizzleTable[2][16];
typedef uint16 Unit;
};
struct STORAGEPSMT8
{
enum PAGEWIDTH { PAGEWIDTH = 128 };
enum PAGEHEIGHT { PAGEHEIGHT = 64 };
enum BLOCKWIDTH { BLOCKWIDTH = 16 };
enum BLOCKHEIGHT { BLOCKHEIGHT = 16 };
enum COLUMNWIDTH { COLUMNWIDTH = 16 };
enum COLUMNHEIGHT { COLUMNHEIGHT = 4 };
static int m_nBlockSwizzleTable[4][8];
static int m_nColumnWordTable[2][2][8];
typedef uint8 Unit;
};
struct STORAGEPSMT4
{
enum PAGEWIDTH { PAGEWIDTH = 128 };
enum PAGEHEIGHT { PAGEHEIGHT = 128 };
enum BLOCKWIDTH { BLOCKWIDTH = 32 };
enum BLOCKHEIGHT { BLOCKHEIGHT = 16 };
enum COLUMNWIDTH { COLUMNWIDTH = 32 };
enum COLUMNHEIGHT { COLUMNHEIGHT = 4 };
static int m_nBlockSwizzleTable[8][4];
static int m_nColumnWordTable[2][2][8];
typedef uint8 Unit;
};
template <typename Storage> class CPixelIndexor
{
public:
CPixelIndexor(uint8* pMemory, uint32 nPointer, uint32 nWidth)
{
m_nPointer = nPointer;
m_nWidth = nWidth;
m_pMemory = pMemory;
}
typename Storage::Unit GetPixel(unsigned int nX, unsigned int nY)
{
return *GetPixelAddress(nX, nY);
}
void SetPixel(unsigned int nX, unsigned int nY, typename Storage::Unit nPixel)
{
*GetPixelAddress(nX, nY) = nPixel;
}
typename Storage::Unit* GetPixelAddress(unsigned int nX, unsigned int nY)
{
uint32 nAddress = GetColumnAddress(nX, nY);
return &((typename Storage::Unit*)&m_pMemory[nAddress])[Storage::m_nColumnSwizzleTable[nY][nX]];
}
private:
uint32 GetColumnAddress(unsigned int& nX, unsigned int& nY)
{
uint32 nPageNum, nBlockNum, nColumnNum;
nPageNum = (nX / Storage::PAGEWIDTH) + (nY / Storage::PAGEHEIGHT) * (m_nWidth * 64) / Storage::PAGEWIDTH;
nX %= Storage::PAGEWIDTH;
nY %= Storage::PAGEHEIGHT;
nBlockNum = Storage::m_nBlockSwizzleTable[nY / Storage::BLOCKHEIGHT][nX / Storage::BLOCKWIDTH];
nX %= Storage::BLOCKWIDTH;
nY %= Storage::BLOCKHEIGHT;
nColumnNum = (nY / Storage::COLUMNHEIGHT);
nY %= Storage::COLUMNHEIGHT;
return (m_nPointer + (nPageNum * PAGESIZE) + (nBlockNum * BLOCKSIZE) + (nColumnNum * COLUMNSIZE)) & (RAMSIZE - 1);
}
enum PAGESIZE
{
PAGESIZE = 8192,
};
enum BLOCKSIZE
{
BLOCKSIZE = 256,
};
enum COLUMNSIZE
{
COLUMNSIZE = 64,
};
uint32 m_nPointer;
uint32 m_nWidth;
uint8* m_pMemory;
};
typedef CPixelIndexor<STORAGEPSMCT32> CPixelIndexorPSMCT32;
typedef CPixelIndexor<STORAGEPSMCT16> CPixelIndexorPSMCT16;
typedef CPixelIndexor<STORAGEPSMCT16S> CPixelIndexorPSMCT16S;
typedef CPixelIndexor<STORAGEPSMT8> CPixelIndexorPSMT8;
typedef CPixelIndexor<STORAGEPSMT4> CPixelIndexorPSMT4;
typedef bool (CGSHandler::*TRANSFERHANDLER)(void*, uint32);
//General Purpose Registers
TEXCLUT* GetTexClut();
FRAME* GetFrame(unsigned int);
FOGCOL* GetFogCol();
TRXREG* GetTrxReg();
TRXPOS* GetTrxPos();
BITBLTBUF* GetBitBltBuf();
//Privileged Regsiters
DISPFB* GetDispFb(unsigned int);
unsigned int GetCrtWidth();
unsigned int GetCrtHeight();
bool GetCrtIsInterlaced();
bool GetCrtIsFrameMode();
void ThreadProc();
virtual void InitializeImpl() = 0;
virtual void FlipImpl() = 0;
virtual void UpdateViewportImpl() = 0;
virtual void WriteRegisterImpl(uint8, uint64);
virtual void FeedImageDataImpl(void*, uint32);
virtual void WriteRegisterMassivelyImpl(const RegisterWrite*, unsigned int);
TRANSFERHANDLER m_pTransferHandler[PSM_MAX];
bool TrxHandlerInvalid(void*, uint32);
template <typename Storage> bool TrxHandlerCopy(void*, uint32);
bool TrxHandlerPSMT4(void*, uint32);
bool TrxHandlerPSMCT24(void*, uint32);
bool TrxHandlerPSMT8H(void*, uint32);
template <uint32, uint32> bool TrxHandlerPSMT4H(void*, uint32);
unsigned int GetPsmPixelSize(unsigned int);
uint64 m_nPMODE; //0x12000000
uint64 m_nDISPFB1; //0x12000070
uint64 m_nDISPLAY1; //0x12000080
uint64 m_nDISPFB2; //0x12000090
uint64 m_nDISPLAY2; //0x120000A0
uint64 m_nCSR; //0x12001000
uint64 m_nIMR; //0x12001010
TRXCONTEXT m_TrxCtx;
uint64 m_nReg[0x80];
uint8* m_pRAM;
unsigned int m_nCrtMode;
bool m_nCrtIsInterlaced;
bool m_nCrtIsFrameMode;
boost::thread* m_thread;
CMailBox m_mailBox;
bool m_enabled;
};
//////////////////////////////////////////////
//Some storage methods templates specializations
template <>
inline uint8 CGSHandler::CPixelIndexor<CGSHandler::STORAGEPSMT4>::GetPixel(unsigned int nX, unsigned int nY)
{
typedef STORAGEPSMT4 Storage;
uint32 nAddress;
unsigned int nColumnNum, nSubTable, nShiftAmount;
nColumnNum = (nY / Storage::COLUMNHEIGHT) & 0x01;
nAddress = GetColumnAddress(nX, nY);
nShiftAmount = (nX & 0x18);
nShiftAmount += (nY & 0x02) << 1;
nSubTable = (nY & 0x02) >> 1;
nSubTable ^= (nColumnNum);
nX &= 0x07;
nY &= 0x01;
return (uint8)(((uint32*)&m_pMemory[nAddress])[Storage::m_nColumnWordTable[nSubTable][nY][nX]] >> nShiftAmount) & 0x0F;
}
template <> void CGSHandler::CPixelIndexor<CGSHandler::STORAGEPSMT4>::SetPixel(unsigned int nX, unsigned int nY, uint8 nPixel)
{
typedef STORAGEPSMT4 Storage;
uint32 nAddress;
unsigned int nColumnNum, nSubTable, nShiftAmount;
nColumnNum = (nY / Storage::COLUMNHEIGHT) & 0x01;
nAddress = GetColumnAddress(nX, nY);
nShiftAmount = (nX & 0x18);
nShiftAmount += (nY & 0x02) << 1;
nSubTable = (nY & 0x02) >> 1;
nSubTable ^= (nColumnNum);
nX &= 0x07;
nY &= 0x01;
uint32* pPixel = &(((uint32*)&m_pMemory[nAddress])[Storage::m_nColumnWordTable[nSubTable][nY][nX]]);
(*pPixel) &= ~(0xF << nShiftAmount);
(*pPixel) |= (nPixel << nShiftAmount);
}
template <>
inline uint8* CGSHandler::CPixelIndexor<CGSHandler::STORAGEPSMT8>::GetPixelAddress(unsigned int nX, unsigned int nY)
{
typedef CGSHandler::STORAGEPSMT8 Storage;
unsigned int nByte, nTable;
uint32 nColumnNum, nOffset;
nColumnNum = (nY / Storage::COLUMNHEIGHT) & 0x01;
nOffset = GetColumnAddress(nX, nY);
nTable = (nY & 0x02) >> 1;
nByte = (nX & 0x08) >> 2;
nByte += (nY & 0x02) >> 1;
nTable ^= (nColumnNum);
nX &= 0x7;
nY &= 0x1;
return reinterpret_cast<uint8*>(&((uint32*)&m_pMemory[nOffset])[Storage::m_nColumnWordTable[nTable][nY][nX]]) + nByte;
}
#endif