/*

	SST Multi-Purpose Flash (MPF)

	(c) 2001-2007 Tim Schuerewegen

	SST39VF020  - 256 KByte
	SST39VF400A - 512 Kbyte

*/

#include "sst39vfx.h"

#define LOG_LEVEL  1
#define _logerror(level,x)  do { if (LOG_LEVEL > level) logerror x; } while (0)

/***************************************************************************
    TYPE DEFINITIONS
***************************************************************************/

typedef struct _sst39vfx_t sst39vfx_t;
struct _sst39vfx_t
{
	UINT8 *data;
	UINT32 size;
	UINT8 swap;
};

enum
{
	TYPE_SST39VF020,
	TYPE_SST39VF400A
};

/***************************************************************************
    INLINE FUNCTIONS
***************************************************************************/

INLINE sst39vfx_t *get_token(const device_config *device)
{
	assert(device != NULL);
	return (sst39vfx_t *) device->token;
}

INLINE const sst39vfx_config *get_config(const device_config *device)
{
	assert(device != NULL);
	return (const sst39vfx_config *) device->inline_config;
}


/***************************************************************************
    IMPLEMENTATION
***************************************************************************/

static void common_start(const device_config *device, int device_type)
{
	sst39vfx_t *flash = get_token(device);
	const sst39vfx_config *config = get_config(device);
	
	_logerror( 0, ("sst39vfx_init (%d)\n", device_type));
	memset( flash, 0, sizeof( flash));
	switch (device_type)
	{
		case TYPE_SST39VF020  : flash->size = 256 * 1024; break;
		case TYPE_SST39VF400A : flash->size = 512 * 1024; break;
	}
	flash->data = auto_malloc( flash->size);
#ifdef LSB_FIRST
	if (config->cpu_endianess != ENDIANNESS_LITTLE) flash->swap = config->cpu_datawidth / 8; else flash->swap = 0;
#else
	if (config->cpu_endianess != ENDIANNESS_BIG) flash->swap = config->cpu_datawidth / 8; else flash->swap = 0;
#endif

	state_save_register_item_pointer(device->machine, "sst39vfx", device->tag, 0, flash->data, flash->size);
	state_save_register_item(device->machine, "sst39vfx", device->tag, 0, flash->swap);
}


static DEVICE_START( sst39vf020 )
{
	common_start(device, TYPE_SST39VF020);
}

static DEVICE_START( sst39vf400a )
{
	common_start(device, TYPE_SST39VF400A);
}

UINT8* sst39vfx_get_base( const device_config *device)
{
	sst39vfx_t *flash = get_token(device);
	return flash->data;
}

UINT32 sst39vfx_get_size( const device_config *device)
{
	sst39vfx_t *flash = get_token(device);
	return flash->size;
}

/*
#define OFFSET_SWAP(offset,width) (offset & (~(width - 1))) | (width - 1 - (offset & (width - 1)))
*/

/*
READ8_HANDLER( sst39vfx_r )
{
	_logerror( 1, ("sst39vfx_r (%08X)\n", offset));
	if (flash->swap) offset = OFFSET_SWAP( offset, flash->swap);
	return flash->data[offset];
}
*/

/*
WRITE8_HANDLER( sst39vfx_w )
{
	_logerror( 1, ("sst39vfx_w (%08X/%02X)\n", offset, data));
	if (flash->swap) offset = OFFSET_SWAP( offset, flash->swap);
	flash->data[offset] = data;
}
*/

static void sst39vfx_swap( const device_config *device)
{
	int i, j;
	UINT8 *base, temp[8];
	sst39vfx_t *flash = get_token(device);
	
	base = flash->data;
	for (i=0;i<flash->size;i+=flash->swap)
	{
		memcpy( temp, base, flash->swap);
		for (j=flash->swap-1;j>=0;j--) *base++ = temp[j];
	}
}

void sst39vfx_load(const device_config *device, mame_file *file)
{
	sst39vfx_t *flash = get_token(device);
	
	_logerror( 0, ("sst39vfx_load (%p)\n", file));
	mame_fread( file, flash->data, flash->size);
	if (flash->swap) sst39vfx_swap(device);
}

void sst39vfx_save(const device_config *device, mame_file *file)
{
	sst39vfx_t *flash = get_token(device);
	
	_logerror( 0, ("sst39vfx_save (%p)\n", file));
	if (flash->swap) sst39vfx_swap(device);
	mame_fwrite( file, flash->data, flash->size);
	if (flash->swap) sst39vfx_swap(device);
}

/*
NVRAM_HANDLER( sst39vfx )
{
	_logerror( 0, ("nvram_handler_sst39vfx (%p/%d)\n", file, read_or_write));
	if (read_or_write)
	{
		sst39vfx_save( file);
	}
	else
	{
		if (file)
		{
			sst39vfx_load( file);
		}
		else
		{
			memset( flash->data, 0xFF, flash->size);
		}
	}
}
*/
/*-------------------------------------------------
    DEVICE_SET_INFO( sst39vfx )
-------------------------------------------------*/

static DEVICE_SET_INFO( sst39vfx )
{
	switch (state)
	{
		/* no parameters to set */
	}
}



/*-------------------------------------------------
    DEVICE_GET_INFO( sst39vf020 )
-------------------------------------------------*/

DEVICE_GET_INFO( sst39vf020 )
{
	switch (state)
	{
		/* --- the following bits of info are returned as 64-bit signed integers --- */
		case DEVINFO_INT_TOKEN_BYTES:					info->i = sizeof(sst39vfx_t);				break;
		case DEVINFO_INT_INLINE_CONFIG_BYTES:			info->i = sizeof(sst39vfx_config);			break;
		case DEVINFO_INT_CLASS:							info->i = DEVICE_CLASS_PERIPHERAL;			break;

		/* --- the following bits of info are returned as pointers to data or functions --- */
		case DEVINFO_FCT_SET_INFO:						info->set_info = DEVICE_SET_INFO_NAME(sst39vfx); break;
		case DEVINFO_FCT_START:							info->start = DEVICE_START_NAME(sst39vf020);	break;
		case DEVINFO_FCT_STOP:							/* Nothing */									break;
		case DEVINFO_FCT_RESET:							/* Nothing */									break;

		/* --- the following bits of info are returned as NULL-terminated strings --- */
		case DEVINFO_STR_NAME:							strcpy(info->s, "SST39VF020");					break;
		case DEVINFO_STR_FAMILY:						strcpy(info->s, "SST39VFxx");					break;
		case DEVINFO_STR_VERSION:						strcpy(info->s, "1.0");							break;
		case DEVINFO_STR_SOURCE_FILE:					strcpy(info->s, __FILE__);						break;
		case DEVINFO_STR_CREDITS:						/* Nothing */									break;
	}
}

DEVICE_GET_INFO( sst39vf400a )
{
	switch (state)
	{
		/* --- the following bits of info are returned as NULL-terminated strings --- */
		case DEVINFO_STR_NAME:							strcpy(info->s, "SST39VF400A");				break;

		/* --- the following bits of info are returned as pointers to data or functions --- */
		case DEVINFO_FCT_START:							info->start = DEVICE_START_NAME(sst39vf400a);	break;

		default: 										DEVICE_GET_INFO_CALL(sst39vf020);				break;
	}
}
