/*
	This 1980s computer was manufactured by Vtech of Hong Kong.
	known as: creatiVision, Dick Smith Wizzard, Funvision, Hanimex Ramses, Laser2001 and possibly others.

	There is also a CreatiVision Mk 2, possibly also known as the Laser 500. This was a proper computer,
	containing a CreatiVision cartridge slot.

    TODO:

    - proper emulation of the monstrous keyboard

*/

#include "driver.h"
#include "cpu/m6502/m6502.h"
#include "devices/cartslot.h"
#include "devices/cassette.h"
#include "machine/6821pia.h"
#include "sound/sn76496.h"
#include "video/tms9928a.h"

#define M6502_TAG	"m6502"
#define SCREEN_TAG	"screen"

/* Memory Map */

static ADDRESS_MAP_START( crvision_map, ADDRESS_SPACE_PROGRAM, 8 )
	AM_RANGE(0x0000, 0x03ff) AM_RAM AM_MIRROR(0x0c00)
	AM_RANGE(0x1000, 0x1003) AM_DEVREADWRITE("pia", pia6821_r, pia6821_w)
	AM_RANGE(0x2000, 0x2000) AM_READ(TMS9928A_vram_r)
	AM_RANGE(0x2001, 0x2001) AM_READ(TMS9928A_register_r)
	AM_RANGE(0x3000, 0x3000) AM_WRITE(TMS9928A_vram_w)
	AM_RANGE(0x3001, 0x3001) AM_WRITE(TMS9928A_register_w)
	AM_RANGE(0x4000, 0x7fff) AM_ROMBANK(2)
	AM_RANGE(0x8000, 0xbfff) AM_ROMBANK(1)
	AM_RANGE(0xc000, 0xc7ff) AM_ROM AM_MIRROR(0x3800)
ADDRESS_MAP_END

/* Input Ports */

static INPUT_PORTS_START( crvision )

	// Player 1 Joystick

	PORT_START("PA0-0")
	PORT_BIT( 0xff, IP_ACTIVE_LOW, IPT_UNUSED )

	PORT_START("PA0-1")
	PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN )
	PORT_BIT( 0xfd, IP_ACTIVE_LOW, IPT_UNUSED )

	PORT_START("PA0-2")
	PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT )
	PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_1) PORT_CHAR('1')
	PORT_BIT( 0xf3, IP_ACTIVE_LOW, IPT_UNUSED )

	PORT_START("PA0-3")
	PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_UP )
	PORT_BIT( 0xf7, IP_ACTIVE_LOW, IPT_UNUSED )

	PORT_START("PA0-4")
	PORT_BIT( 0xff, IP_ACTIVE_LOW, IPT_UNUSED )

	PORT_START("PA0-5")
	PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT )
	PORT_BIT( 0xdf, IP_ACTIVE_LOW, IPT_UNUSED )

	PORT_START("PA0-6")
	PORT_BIT( 0xff, IP_ACTIVE_LOW, IPT_UNUSED )

	PORT_START("PA0-7")
	PORT_BIT( 0x7f, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("P1 Button 2 / CNT'L") PORT_CODE(KEYCODE_LCONTROL) PORT_CODE(KEYCODE_RCONTROL)

	// Player 1 Keyboard

	PORT_START("PA1-0")
	PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F) PORT_CHAR('F')
	PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_G) PORT_CHAR('G')
	PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("<-") PORT_CODE(KEYCODE_BACKSPACE) PORT_CHAR(8)
	PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_A) PORT_CHAR('A')
	PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_S) PORT_CHAR('S')
	PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_D) PORT_CHAR('D')
	PORT_BIT( 0x81, IP_ACTIVE_LOW, IPT_UNUSED )

	PORT_START("PA1-1")
	PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_B) PORT_CHAR('B')
	PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Z) PORT_CHAR('Z')
	PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_X) PORT_CHAR('X')
	PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_C) PORT_CHAR('C')
	PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_V) PORT_CHAR('V')
	PORT_BIT( 0x83, IP_ACTIVE_LOW, IPT_UNUSED )

	PORT_START("PA1-2")
	PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_W) PORT_CHAR('W')
	PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_E) PORT_CHAR('E')
	PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_R) PORT_CHAR('R')
	PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_T) PORT_CHAR('T')
	PORT_BIT( 0x87, IP_ACTIVE_LOW, IPT_UNUSED )

	PORT_START("PA1-3")
	PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Q) PORT_CHAR('Q')
	PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$')
	PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%')
	PORT_BIT( 0x8f, IP_ACTIVE_LOW, IPT_UNUSED )

	PORT_START("PA1-4")
	PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('"')
	PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('&')
	PORT_BIT( 0x9f, IP_ACTIVE_LOW, IPT_UNUSED )

	PORT_START("PA1-5")
	PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#')
	PORT_BIT( 0xbf, IP_ACTIVE_LOW, IPT_UNUSED )

	PORT_START("PA1-6")
	PORT_BIT( 0xff, IP_ACTIVE_LOW, IPT_UNUSED )

	PORT_START("PA1-7")
	PORT_BIT( 0x7f, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("P1 Button 1 / SHIFT") PORT_CODE(KEYCODE_LSHIFT) PORT_CODE(KEYCODE_RSHIFT)

	// Player 2 Joystick

	PORT_START("PA2-0")
	PORT_BIT( 0xff, IP_ACTIVE_LOW, IPT_UNUSED )

	PORT_START("PA2-1")
	PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(2)
	PORT_BIT( 0xfd, IP_ACTIVE_LOW, IPT_UNUSED )

	PORT_START("PA2-2")
	PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(2)
	PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("SPACE") PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ')
	PORT_BIT( 0xf3, IP_ACTIVE_LOW, IPT_UNUSED )

	PORT_START("PA2-3")
	PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(2)
	PORT_BIT( 0xf7, IP_ACTIVE_LOW, IPT_UNUSED )

	PORT_START("PA2-4")
	PORT_BIT( 0xff, IP_ACTIVE_LOW, IPT_UNUSED )

	PORT_START("PA2-5")
	PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(2)
	PORT_BIT( 0xdf, IP_ACTIVE_LOW, IPT_UNUSED )

	PORT_START("PA2-6")
	PORT_BIT( 0xff, IP_ACTIVE_LOW, IPT_UNUSED )

	PORT_START("PA2-7")
	PORT_BIT( 0x7f, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("P2 Button 2 / ->") PORT_CODE(KEYCODE_TAB) PORT_CHAR(9) PORT_PLAYER(2)

	// Player 2 Keyboard

	PORT_START("PA3-0")
	PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_U) PORT_CHAR('U')
	PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Y) PORT_CHAR('Y')
	PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("RET'N") PORT_CODE(KEYCODE_ENTER) PORT_CHAR('\r')
	PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_P) PORT_CHAR('P')
	PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_O) PORT_CHAR('O')
	PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_I) PORT_CHAR('I')
	PORT_BIT( 0x81, IP_ACTIVE_LOW, IPT_UNUSED )

	PORT_START("PA3-1")
	PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_7) PORT_CHAR('7') PORT_CHAR('\'')
	PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR(':') PORT_CHAR('*')
	PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_0) PORT_CHAR('0') PORT_CHAR('@')
	PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_9) PORT_CHAR('9') PORT_CHAR(')')
	PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_8) PORT_CHAR('8') PORT_CHAR('(')
	PORT_BIT( 0x83, IP_ACTIVE_LOW, IPT_UNUSED )

	PORT_START("PA3-2")
	PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_L) PORT_CHAR('L')
	PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_K) PORT_CHAR('K')
	PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_J) PORT_CHAR('J')
	PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_H) PORT_CHAR('H')
	PORT_BIT( 0x87, IP_ACTIVE_LOW, IPT_UNUSED )

	PORT_START("PA3-3")
	PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR(';') PORT_CHAR('+')
	PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<')
	PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_M) PORT_CHAR('M')
	PORT_BIT( 0x8f, IP_ACTIVE_LOW, IPT_UNUSED )

	PORT_START("PA3-4")
	PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?')
	PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_N) PORT_CHAR('N')
	PORT_BIT( 0x9f, IP_ACTIVE_LOW, IPT_UNUSED )

	PORT_START("PA3-5")
	PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>')
	PORT_BIT( 0xbf, IP_ACTIVE_LOW, IPT_UNUSED )

	PORT_START("PA3-6")
	PORT_BIT( 0xff, IP_ACTIVE_LOW, IPT_UNUSED )

	PORT_START("PA3-7")
	PORT_BIT( 0x7f, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("P2 Button 1 / - =") PORT_CODE(KEYCODE_MINUS) PORT_CHAR('-') PORT_CHAR('=') PORT_PLAYER(2)
INPUT_PORTS_END

/* Machine Interface */

static INTERRUPT_GEN( crvision_int )
{
    TMS9928A_interrupt(device->machine);
}

static void crvision_vdp_interrupt(running_machine *machine, int state)
{
	cpu_set_input_line(machine->cpu[0], INPUT_LINE_IRQ0, state);
}

static const TMS9928a_interface tms9918_intf =
{
	TMS99x8,
	0x4000,
	0, 0,
	crvision_vdp_interrupt
};

static const TMS9928a_interface tms9929_intf =
{
	TMS9929,
	0x4000,
	0, 0,
	crvision_vdp_interrupt
};

static int keylatch;

static WRITE8_DEVICE_HANDLER( crvision_pia_porta_w )
{
	/*
        Signal  Description

        PA0     Keyboard raster player 1 output
        PA1     Keyboard raster player 1 output
        PA2     Keyboard raster player 2 output
        PA3     Keyboard raster player 2 output
        PA4     ?
        PA5     ?
        PA6     ?
        PA7     ?
    */

	keylatch = ~data & 0x0f;
}

static UINT8 read_keyboard(running_machine *machine, int pa)
{
	int i;
	UINT8 value;
	static const char *const keynames[4][8] =
			{
				{ "PA0-0", "PA0-1", "PA0-2", "PA0-3", "PA0-4", "PA0-5", "PA0-6", "PA0-7" },
				{ "PA1-0", "PA1-1", "PA1-2", "PA1-3", "PA1-4", "PA1-5", "PA1-6", "PA1-7" },
				{ "PA2-0", "PA2-1", "PA2-2", "PA2-3", "PA2-4", "PA2-5", "PA2-6", "PA2-7" },
				{ "PA3-0", "PA3-1", "PA3-2", "PA3-3", "PA3-4", "PA3-5", "PA3-6", "PA3-7" }
			};

	for (i = 0; i < 8; i++)
	{
		value = input_port_read(machine, keynames[pa][i]);

		if (value != 0xff)
		{
			if (value == 0xff - (1 << i))
				return value;
			else
				return value - (1 << i);
		}
	}

	return 0xff;
}

static READ8_DEVICE_HANDLER( crvision_pia_porta_r )
{
	/*
        PA0     Keyboard raster player 1 output
        PA1     Keyboard raster player 1 output
        PA2     Keyboard raster player 2 output
        PA3     Keyboard raster player 2 output
        PA4     ?
        PA5     ?
        PA6     ?
        PA7     ?
    */

	return 0xff;
}

static READ8_DEVICE_HANDLER( crvision_pia_portb_r )
{
	/*
        Signal  Description

        PB0     Keyboard input
        PB1     Keyboard input
        PB2     Keyboard input
        PB3     Keyboard input
        PB4     Keyboard input
        PB5     Keyboard input
        PB6     Keyboard input
        PB7     Keyboard input
    */

	if (keylatch & 0x01)
	{
		return read_keyboard(device->machine, 0);
	}
	else if (keylatch & 0x02)
	{
		return read_keyboard(device->machine, 1);
	}
	else if (keylatch & 0x04)
	{
		return read_keyboard(device->machine, 2);
	}
	else if (keylatch & 0x08)
	{
		return read_keyboard(device->machine, 3);
	}

	return 0xff;
}

static READ8_DEVICE_HANDLER( crvision_pia_ca1_r )
{
	return 1;
}

static READ8_DEVICE_HANDLER( crvision_pia_ca2_r )
{
	return 1;
}

static int sn76489_ready;

static READ8_DEVICE_HANDLER( crvision_pia_cb1_r )
{
	return sn76489_ready;
}

static TIMER_CALLBACK(sn76489_set_ready)
{
	sn76489_ready = 1;
}

static WRITE8_DEVICE_HANDLER( crvision_pia_portb_w )
{
	/*
        Signal  Description

        PB0     SN76489 data output
        PB1     SN76489 data output
        PB2     SN76489 data output
        PB3     SN76489 data output
        PB4     SN76489 data output
        PB5     SN76489 data output
        PB6     SN76489 data output
        PB7     SN76489 data output
    */

	const device_config *sn76489 = devtag_get_device(device->machine, "sn76489");
	sn76496_w(sn76489, 0, data);

	sn76489_ready = 0;

	// wait 32 cycles of 2 MHz to synchronize CPU and SN76489
	timer_set(device->machine, ATTOTIME_IN_USEC(16), NULL, 0, sn76489_set_ready);
}

static WRITE8_DEVICE_HANDLER( crvision_pia_cb2_w )
{
	sn76489_ready = data & 0x01;
}

static const pia6821_interface crvision_pia_intf =
{
	DEVCB_HANDLER(crvision_pia_porta_r),	// input A
	DEVCB_HANDLER(crvision_pia_portb_r),	// input B
	DEVCB_HANDLER(crvision_pia_ca1_r),		// input CA1 (+5V)
	DEVCB_HANDLER(crvision_pia_cb1_r),		// input CB1 (SN76489 pin READY )
	DEVCB_HANDLER(crvision_pia_ca2_r),		// input CA2 (+5V)
	DEVCB_NULL,								// input CB2
	DEVCB_HANDLER(crvision_pia_porta_w),	// output A
	DEVCB_HANDLER(crvision_pia_portb_w),	// output B (SN76489 pins D0-D7)
	DEVCB_NULL,								// output CA2
	DEVCB_HANDLER(crvision_pia_cb2_w),		// output CB2 (SN76489 pin CE_)
	DEVCB_NULL,								// irq A
	DEVCB_NULL								// irq B
};

static MACHINE_START( crvision )
{
	state_save_register_global(machine, keylatch);
	state_save_register_global(machine, sn76489_ready);

	TMS9928A_configure(&tms9918_intf);
}

static MACHINE_START( fnvision )
{
	state_save_register_global(machine, keylatch);
	state_save_register_global(machine, sn76489_ready);

	TMS9928A_configure(&tms9929_intf);
}


static DEVICE_IMAGE_LOAD( crvision_cart )
{
	int size = image_length(image);
	running_machine *machine = image->machine;
	UINT8 *mem = memory_region(machine, M6502_TAG);

	switch (size)
	{
	case 0x1000: // 4K
		image_fread(image, mem + 0x9000, 0x1000);
		memory_install_read8_handler(cpu_get_address_space(machine->cpu[0], ADDRESS_SPACE_PROGRAM), 0x8000, 0x9fff, 0, 0x2000, SMH_BANK1);
		break;

	case 0x1800: // 6K
		image_fread(image, mem + 0x9000, 0x1000);
		image_fread(image, mem + 0x8800, 0x0800);
		memory_install_read8_handler(cpu_get_address_space(machine->cpu[0], ADDRESS_SPACE_PROGRAM), 0x8000, 0x9fff, 0, 0x2000, SMH_BANK1);
		break;

	case 0x2000: // 8K
		image_fread(image, mem + 0x8000, 0x2000);
		memory_install_read8_handler(cpu_get_address_space(machine->cpu[0], ADDRESS_SPACE_PROGRAM), 0x8000, 0x9fff, 0, 0x2000, SMH_BANK1);
		break;

	case 0x2800: // 10K
		image_fread(image, mem + 0x8000, 0x2000);
		image_fread(image, mem + 0x5800, 0x0800);
		memory_install_read8_handler(cpu_get_address_space(machine->cpu[0], ADDRESS_SPACE_PROGRAM), 0x8000, 0x9fff, 0, 0x2000, SMH_BANK1);
		memory_install_read8_handler(cpu_get_address_space(machine->cpu[0], ADDRESS_SPACE_PROGRAM), 0x4000, 0x5fff, 0, 0x2000, SMH_BANK2);
		break;

	case 0x3000: // 12K
		image_fread(image, mem + 0x8000, 0x2000);
		image_fread(image, mem + 0x5000, 0x1000);
		memory_install_read8_handler(cpu_get_address_space(machine->cpu[0], ADDRESS_SPACE_PROGRAM), 0x8000, 0x9fff, 0, 0x2000, SMH_BANK1);
		memory_install_read8_handler(cpu_get_address_space(machine->cpu[0], ADDRESS_SPACE_PROGRAM), 0x4000, 0x5fff, 0, 0x2000, SMH_BANK2);
		break;

	case 0x4000: // 16K
		image_fread(image, mem + 0xa000, 0x2000);
		image_fread(image, mem + 0x8000, 0x2000);
		memory_install_read8_handler(cpu_get_address_space(machine->cpu[0], ADDRESS_SPACE_PROGRAM), 0x8000, 0xbfff, 0, 0, SMH_BANK1);
		break;

	case 0x4800: // 18K
		image_fread(image, mem + 0xa000, 0x2000);
		image_fread(image, mem + 0x8000, 0x2000);
		image_fread(image, mem + 0x4800, 0x0800);
		memory_install_read8_handler(cpu_get_address_space(machine->cpu[0], ADDRESS_SPACE_PROGRAM), 0x8000, 0x8fff, 0, 0, SMH_BANK1);
		memory_install_read8_handler(cpu_get_address_space(machine->cpu[0], ADDRESS_SPACE_PROGRAM), 0x4000, 0x4fff, 0, 0x3000, SMH_BANK2);
		break;

	default:
		return INIT_FAIL;
	}

	memory_configure_bank(machine, 1, 0, 1, mem + 0x8000, 0);
	memory_set_bank(machine, 1, 0);

	memory_configure_bank(machine, 2, 0, 1, mem + 0x4000, 0);
	memory_set_bank(machine, 2, 0);

	return INIT_PASS;
}

/* Machine Driver */

static MACHINE_DRIVER_START( crvision )
	// basic machine hardware
	MDRV_CPU_ADD(M6502_TAG, M6502, 2000000)
	MDRV_CPU_PROGRAM_MAP(crvision_map, 0)
	MDRV_CPU_VBLANK_INT(SCREEN_TAG, crvision_int)

	MDRV_MACHINE_START( crvision )

    // video hardware
	MDRV_IMPORT_FROM(tms9928a)
	MDRV_SCREEN_MODIFY(SCREEN_TAG)
	MDRV_SCREEN_REFRESH_RATE(10738635.0/2/342/262)
	MDRV_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500)) /* not accurate */

	MDRV_PIA6821_ADD( "pia", crvision_pia_intf )

	// sound hardware
	MDRV_SPEAKER_STANDARD_MONO("mono")
	MDRV_SOUND_ADD("sn76489", SN76489, 2000000)
	MDRV_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.00)

	MDRV_CASSETTE_ADD( "cassette", default_cassette_config )

	/* cartridge */
	MDRV_CARTSLOT_ADD("cart")
	MDRV_CARTSLOT_EXTENSION_LIST("bin,rom")
	MDRV_CARTSLOT_MANDATORY
	MDRV_CARTSLOT_LOAD(crvision_cart)
MACHINE_DRIVER_END

static MACHINE_DRIVER_START( fnvision )
	MDRV_IMPORT_FROM( crvision )
	MDRV_MACHINE_START( fnvision )
	MDRV_SCREEN_MODIFY(SCREEN_TAG)
	MDRV_SCREEN_REFRESH_RATE(10738635.0/2/342/313)

	MDRV_CASSETTE_REMOVE( "cassette" )
MACHINE_DRIVER_END

/* ROMs */

ROM_START( crvision )
    ROM_REGION( 0x10000, M6502_TAG, 0 )
    ROM_LOAD( "crvision.rom", 0xc000, 0x0800, CRC(c3c590c6) SHA1(5ac620c529e4965efb5560fe824854a44c983757) )
ROM_END

ROM_START( fnvision )
    ROM_REGION( 0x10000, M6502_TAG, 0 )
    ROM_LOAD( "funboot.rom", 0xc000, 0x0800, CRC(05602697) SHA1(c280b20c8074ba9abb4be4338b538361dfae517f) )
ROM_END

/* System Drivers */

/*    YEAR  NAME      PARENT    COMPAT  MACHINE     INPUT       INIT    CONFIG      COMPANY             FULLNAME */
COMP( 1981, crvision, 0,		0,		crvision,	crvision,	0,		0,	"Video Technology", "CreatiVision (NTSC)", GAME_SUPPORTS_SAVE )
CONS( 1983, fnvision, crvision, 0,		fnvision,	crvision,	0,		0,	"Video Technology", "FunVision Computer Video Games System (PAL)", GAME_SUPPORTS_SAVE )
