/*
 *   dismem.c
 *
 *   This file is part of Emu48
 *
 *   Copyright (C) 2012 Christoph Gießelink
 *
 */
#include "pch.h"
#include "Emu48.h"

typedef struct								// type of model memory mapping
{
	BYTE         byType;					// calculator type
	CONST LPBYTE *ppbyNCE1;					// NCE1 data
	CONST DWORD  *pdwNCE1Size;				// NCE1 size
	CONST LPBYTE *ppbyNCE2;					// NCE2 data
	CONST DWORD  *pdwNCE2Size;				// NCE2 size
	CONST LPBYTE *ppbyCE1;					// CE1 data
	CONST DWORD  *pdwCE1Size;				// CE1 size
	CONST LPBYTE *ppbyCE2;					// CE2 data
	CONST DWORD  *pdwCE2Size;				// CE2 size
	CONST LPBYTE *ppbyNCE3;					// NCE3 data
	CONST DWORD  *pdwNCE3Size;				// NCE3 size
} MODEL_MAP_T;

static CONST LPBYTE pbyNoMEM = NULL;		// no memory module

static CONST MODEL_MAP_T MemMap[] =
{
	{
		0,									// default
		&pbyNoMEM, NULL,					// nc.
		&pbyNoMEM, NULL,					// nc.
		&pbyNoMEM, NULL,					// nc.
		&pbyNoMEM, NULL,					// nc.
		&pbyNoMEM, NULL						// nc.
	},
	{
		'6',								// HP38G (64K)
		&pbyRom,   &dwRomSize,				// ROM
		&Port0,    &Chipset.Port0Size,		// RAM
		&pbyNoMEM, NULL,					// nc.
		&pbyNoMEM, NULL,					// nc.
		&pbyNoMEM, NULL						// nc.
	},
	{
		'A',								// HP38G
		&pbyRom,   &dwRomSize,				// ROM
		&Port0,    &Chipset.Port0Size,		// RAM
		&pbyNoMEM, NULL,					// nc.
		&pbyNoMEM, NULL,					// nc.
		&pbyNoMEM, NULL						// nc.
	},
	{
		'E',								// HP39/40G
		&pbyRom,   &dwRomSize,				// ROM
		&Port0,    &Chipset.Port0Size,		// RAM part 1
		&pbyNoMEM, NULL,					// BS
		&pbyNoMEM, NULL,					// nc.
		&Port2,    &Chipset.Port2Size		// RAM part 2
	},
	{
		'G',								// HP48GX
		&pbyRom,   &dwRomSize,				// ROM
		&Port0,    &Chipset.Port0Size,		// RAM
		&pbyNoMEM, NULL,					// BS
		&Port1,    &Chipset.Port1Size,		// Card slot 1
		&pbyPort2, &dwPort2Size				// Card slot 2
	},
	{
		'S',								// HP48SX
		&pbyRom,   &dwRomSize,				// ROM
		&Port0,    &Chipset.Port0Size,		// RAM
		&Port1,    &Chipset.Port1Size,		// Card slot 1
		&pbyPort2, &dwPort2Size,			// Card slot 2
		&pbyNoMEM, NULL						// nc.
	},
	{
		'X',								// HP49G
		&pbyRom,   &dwRomSize,				// Flash
		&Port0,    &Chipset.Port0Size,		// RAM
		&pbyNoMEM, NULL,					// BS
		&Port1,    &Chipset.Port1Size,		// Port 1 part 1
		&Port2,    &Chipset.Port2Size		// Port 1 part 2
	},
	{ // CdB for HP: add Q type
		'Q',								// HP49g+
		&pbyRom,   &dwRomSize,				// Flash
		&Port0,	   &Chipset.Port0Size,		// RAM
		&pbyNoMEM, NULL,					// BS
		&Port1,    &Chipset.Port1Size,		// Port 1 part 1
		&Port2,    &Chipset.Port2Size		// Port 1 part 2
	},
	{ // CdB for HP: add 2 type
		'2',								// HP48gII
		&pbyRom,   &dwRomSize,				// ROM
		&Port0,	   &Chipset.Port0Size,		// RAM
		&pbyNoMEM, NULL,					// BS
		&pbyNoMEM, NULL,					// Port 1 part 1
		&pbyNoMEM, NULL,					// Port 1 part 2
	},
	{ // CdB for HP: add P type
		'P',								// HP39g+/gs
		&pbyRom,   &dwRomSize,				// ROM
		&Port0,	   &Chipset.Port0Size,		// RAM
		&pbyNoMEM, NULL,					// BS
		&pbyNoMEM, NULL,					// nc.
		&Port2,	   &Chipset.Port2Size		// RAM part 2
	}
};

static MODEL_MAP_T CONST *pMapping = MemMap; // model specific memory mapping
static enum MEM_MAPPING eMapType = MEM_MMU;	// MMU memory mapping

static LPBYTE pbyMapData = NULL;
static DWORD  dwMapDataSize = 0;
static DWORD  dwMapDataMask = 0;

BOOL SetMemRomType(BYTE cCurrentRomType)
{
	UINT i;

	pMapping = MemMap;						// init default mapping

	// scan for all table entries
	for (i = 0; i < ARRAYSIZEOF(MemMap); ++i)
	{
		if (MemMap[i].byType == cCurrentRomType)
		{
			pMapping = &MemMap[i];			// found entry
			return TRUE;
		}
	}
	return FALSE;
}

BOOL SetMemMapType(enum MEM_MAPPING eType)
{
	BOOL bSucc = TRUE;

	eMapType = eType;

	switch (eMapType)
	{
	case MEM_MMU:
		pbyMapData = NULL;					// data
		dwMapDataSize = 512 * 1024 * 2;		// data size
		dwMapDataMask = dwMapDataSize - 1;	// size mask
		break;
	case MEM_NCE1:
		pbyMapData = *pMapping->ppbyNCE1;
		dwMapDataSize = *pMapping->pdwNCE1Size; // ROM size is always in nibbles
		dwMapDataMask = dwMapDataSize - 1;	// size mask
		break;
	case MEM_NCE2:
		pbyMapData = *pMapping->ppbyNCE2;
		dwMapDataSize = *pMapping->pdwNCE2Size * 1024 * 2;
		dwMapDataMask = dwMapDataSize - 1;	// size mask
		break;
	case MEM_CE1:
		pbyMapData = *pMapping->ppbyCE1;
		dwMapDataSize = *pMapping->pdwCE1Size * 1024 * 2;
		dwMapDataMask = dwMapDataSize - 1;	// size mask
		break;
	case MEM_CE2:
		pbyMapData = *pMapping->ppbyCE2;
		dwMapDataSize = *pMapping->pdwCE2Size * 1024 * 2;
		dwMapDataMask = dwMapDataSize - 1;	// size mask
		break;
	case MEM_NCE3:
		pbyMapData = *pMapping->ppbyNCE3;
		dwMapDataSize = *pMapping->pdwNCE3Size * 1024 * 2;
		dwMapDataMask = dwMapDataSize - 1;	// size mask
		break;
	default: _ASSERT(FALSE);
		pbyMapData = NULL;
		dwMapDataSize = 0;
		dwMapDataMask = 0;
		bSucc = FALSE;
	}
	return bSucc;
}

enum MEM_MAPPING GetMemMapType(VOID)
{
	return eMapType;
}

BOOL GetMemAvail(enum MEM_MAPPING eType)
{
	switch (eType)
	{
	case MEM_MMU:  return TRUE;
	case MEM_NCE1: return *pMapping->ppbyNCE1 != NULL;
	case MEM_NCE2: return *pMapping->ppbyNCE2 != NULL;
	case MEM_CE1:  return *pMapping->ppbyCE1  != NULL;
	case MEM_CE2:  return *pMapping->ppbyCE2  != NULL;
	case MEM_NCE3: return *pMapping->ppbyNCE3 != NULL;
	default: _ASSERT(FALSE);
	}
	return FALSE;
}

DWORD GetMemDataSize(VOID)
{
	return dwMapDataSize;
}

DWORD GetMemDataMask(VOID)
{
	return dwMapDataMask;
}

BYTE GetMemNib(DWORD *p)
{
	BYTE byVal;

	if (pbyMapData == NULL)
	{
		Npeek(&byVal, *p, 1);
	}
	else
	{
		byVal = pbyMapData[*p];
	}
	*p = (*p + 1) & dwMapDataMask;
	return byVal;
}

VOID GetMemPeek(BYTE *a, DWORD d, UINT s)
{
	if (pbyMapData == NULL)
	{
		Npeek(a, d, s);
	}
	else
	{
		for (; s > 0; --s, ++d)
		{
			*a++ = pbyMapData[d & dwMapDataMask];
		}
	}
	return;
}
