#include "burnint.h"

#include "okim6295.h"

const int TOA_68K_SPEED = 16000000;
const int TOA_Z80_SPEED = 4000000;
const int TOA_VBLANK_LINES = 0x10;

// toaplan.cpp
int ToaLoadCode(unsigned char *Rom, int nStart, int nCount);
int ToaLoadGP9001Tiles(unsigned char* pDest, int nStart, int nNumFiles, int nROMSize, bool bSwap = false);

void ToaClearScreen();

void ToaZExit();

extern unsigned char* RomZ80;
extern unsigned char* RamZ80;

extern int nCyclesDone[2], nCyclesTotal[2];
extern int nCyclesSegment;

extern bool bRotatedScreen;

extern unsigned char* pBurnBitmap;
extern int nBurnColumn;
extern int nBurnRow;

inline void ToaGetBitmap()
{
	if (bRotatedScreen) {
		pBurnBitmap = pBurnDraw + 319 * nBurnPitch;
		nBurnColumn = -nBurnPitch;
		nBurnRow = nBurnBpp;
	} else {
		pBurnBitmap = pBurnDraw;
		nBurnColumn = nBurnBpp;
		nBurnRow = nBurnPitch;
	}
}

inline void ToaClearOpposites(unsigned char* nJoystickInputs)
{
	if ((*nJoystickInputs & 0x03) == 0x03) {
		*nJoystickInputs &= ~0x03;
	}
	if ((*nJoystickInputs & 0x0C) == 0x0C) {
		*nJoystickInputs &= ~0x0C;
	}
}

// toa_pal.cpp
extern unsigned char *ToaPalSrc;
extern unsigned int* ToaPalette;
extern unsigned char ToaRecalcPalette;
extern int nToaPalLen;

int ToaPalInit();
int ToaPalExit();
int ToaPalUpdate();

// toa_gp9001.cpp
extern unsigned char* GP9001ROM[2];
extern unsigned int nGP9001ROMSize[2];

extern unsigned int GP9001TileBank[8];

extern unsigned char* GP9001RAM[2];
extern unsigned short* GP9001Reg[2];

extern int nSpriteXOffset, nSpriteYOffset, nSpritePriority;

extern int nLayer0XOffset, nLayer0YOffset, nLayer0Priority;
extern int nLayer1XOffset, nLayer1YOffset, nLayer1Priority;
extern int nLayer2XOffset, nLayer2YOffset, nLayer2Priority;

int ToaBufferGP9001Sprites();
int ToaRenderGP9001();
int ToaInitGP9001(int n = 1);
int ToaExitGP9001();

inline static void ToaGP9001SetRAMPointer(unsigned int wordValue, const int nController = 0)
{
	extern unsigned char* GP9001Pointer[2];

	wordValue &= 0x1FFF;
	GP9001Pointer[nController] = GP9001RAM[nController] + (wordValue << 1);
}

inline static void ToaGP9001WriteRAM(const unsigned short wordValue, const int nController)
{
	extern unsigned char* GP9001Pointer[2];

	*((unsigned short*)(GP9001Pointer[nController])) = wordValue;
	GP9001Pointer[nController] += 2;
}

inline static unsigned short ToaGP9001ReadRAM_Hi(const int nController)
{
	extern unsigned char* GP9001Pointer[2];
	
	return *((unsigned short*)(GP9001Pointer[nController]));
}

inline static unsigned short ToaGP9001ReadRAM_Lo(const int nController)
{
	extern unsigned char* GP9001Pointer[2];
	
	return *((unsigned short*)(GP9001Pointer[nController] + 2));
}

inline static void ToaGP9001SelectRegister(const unsigned short wordValue, const int nController = 0)
{
	extern int GP9001Regnum[2];

	GP9001Regnum[nController] = wordValue & 0xFF;
}

inline static void ToaGP9001WriteRegister(const unsigned short wordValue, const int nController = 0)
{
	extern int GP9001Regnum[2];

	GP9001Reg[nController][GP9001Regnum[nController]] = wordValue;
}

inline unsigned short ToaVBlankRegister()
{
	int nCycles = (nCyclesDone[0] + nCyclesSegment - m68k_ICount);
	
	if (nCycles >= (0x0106 - TOA_VBLANK_LINES) * ((TOA_68K_SPEED / 60) / 0x0106)) {
		return 1;
	} else {
		if (nCycles < (0x0106 - 224 - TOA_VBLANK_LINES) * ((TOA_68K_SPEED / 60) / 0x0106)) {
			return 1;
		}
	}
	return 0;
}

inline unsigned short ToaScanlineRegister()
{
	static int nPreviousScanline;
	int nCurrentScanline = (nCyclesDone[0] + nCyclesSegment - m68k_ICount) / ((TOA_68K_SPEED / 60) / 0x0106);
	unsigned short n = 0xFE00;

#if 0
	// None of the games actually use this
	int nCurrentBeamPosition = (nCyclesDone[0] + nCyclesSegment - m68k_ICount) % ((TOA_68K_SPEED / 60) / 0x0106);
	if (nCurrentBeamPosition < 64) {
		n &= ~0x4000;
	}
#endif

	if (nCurrentScanline != nPreviousScanline) {
		nPreviousScanline = nCurrentScanline;
		n &= ~0x8000;
	}

	return n | nCurrentScanline;
}

// toa_extratext.cpp
extern unsigned char* ExtraTROM;
extern unsigned char* ExtraTRAM;
extern unsigned char* ExtraTOffset;
extern unsigned char* ExtraTScroll;
extern int nExtraTXOffset;

int ToaExtraTextLayer();
int ToaExtraTextInit();
void ToaExtraTextExit();

// toa_ym2151.cpp
extern "C" {
 #include "driver.h"
 #include "ym2151.h"
}

int ToaYM2151Init(int nClockFrequency);
void ToaYM2151Exit();
void ToaYM2151Scan(int nAction);

extern short* pYM2151Buffer[2];

extern unsigned char ToaYM2151Registers[0x0100];
extern unsigned int ToaCurrentYM2151Register;

inline void ToaYM2151SelectRegister(unsigned char nRegister)
{
	ToaCurrentYM2151Register = nRegister;
}

inline void ToaYM2151WriteRegister(unsigned char nValue)
{
	ToaYM2151Registers[ToaCurrentYM2151Register] = nValue;
	YM2151WriteReg(0, ToaCurrentYM2151Register, nValue);
}

// toa_ymz280b.cpp
int YMZ280BInit(int nSamplerate);
void YMZ280BExit();
int YMZ280BRender(short* pSoundBuf, int nSegmenLength);
void YMZ280BWriteRegister(unsigned char nValue);

extern unsigned char* YMZ280BROM;

extern unsigned int nYMZ280BStatus;
extern unsigned int nYMZ280BRegister;

inline void YMZ280BSelectRegister(unsigned char nRegister)
{
	nYMZ280BRegister = nRegister;
}

inline unsigned int YMZ280BReadStatus()
{
	unsigned int nStatus = nYMZ280BStatus;
	nYMZ280BStatus = 0;
	return nStatus;
}

