/******************************************************************************

        nc.c

        NC100/NC150/NC200 Notepad computer

        system driver


		Thankyou to:
			Cliff Lawson, Russell Marks and Tim Surtel

        Documentation:

		NC100:
			NC100 I/O Specification by Cliff Lawson,
			NC100EM by Russell Marks
		NC200:
			Dissassembly of the NC200 ROM + e-mail
			exchange with Russell Marks


		NC100:

        Hardware:
            - Z80 CPU, 6mhz
            - memory powered by lithium batterys!
            - 2 channel tone (programmable frequency beep's)
            - LCD screen
            - laptop/portable computer
            - qwerty keyboard
            - serial/parallel connection
            - Amstrad custom ASIC chip
			- tc8521 real time clock
			- intel 8251 compatible uart
			- PCMCIA Memory cards supported, up to 1mb!

		NC200:

        Hardware:
			- Z80 CPU
			- Intel 8251 compatible uart
            - nec765 compatible floppy disc controller
			- mc146818 real time clock?
			- 720k floppy disc drive (compatible with MS-DOS)
			(disc drive can be not ready).
			- PCMCIA Memory cards supported, up to 1mb!

        TODO:
           - find out what the unused key bits are for
		   (checked all unused bits on nc200! - do not seem to have any use!)
           - complete serial (xmodem protocol!)
		   - overlay would be nice!
		   - finish NC200 disc drive emulation (closer!)
		   - add NC150 driver - ROM needed!!!
			- on/off control
			- check values read from other ports that are not described!
			- what is read from unmapped ports?
			- what is read from uart when it is off?
			- check if uart ints are generated when it is off?
			- are ints cancelled if uart is turned off after int has been caused?
			- check keyboard ints - are these regular or what??

		PCMCIA memory cards are stored as a direct dump of the contents. There is no header
		information. No distinction is made between RAM and ROM cards.

		Memory card sizes are a power of 2 in size (e.g. 1mb, 512k, 256k etc),
		however the code allows any size, but it limits access to power of 2 sizes, with
		minimum access being 16k. If a file which is less than 16k is used, no memory card
		will be present. If a file which is greater than 1mb is used, only 1mb will be accessed.

		Interrupt system of NC100:

		The IRQ mask is used to control the interrupt sources that can interrupt.

		The IRQ status can be read to determine which devices are interrupting.
		Some devices, e.g. serial, cannot be cleared by writing to the irq status
		register. These can only be cleared by performing an operation on the
		device (e.g. reading a data register).

		Self Test:

		- requires memory save and real time clock save to be working!
		(i.e. for MESS nc100 driver, nc100.nv can be created)
		- turn off nc (use NMI button)
		- reset+FUNCTION+SYMBOL must be pressed together.

		Note: NC200 Self test does not test disc hardware :(



		Kevin Thacker [MESS driver]

 ******************************************************************************/
#include "driver.h"
#include "machine/mc146818.h"	/* for NC200 real time clock */
#include "includes/nc.h"
#include "includes/tc8521.h"	/* for NC100 real time clock */
#include "includes/msm8251.h"	/* for NC100 uart */
#include "machine/nec765.h"	/* for NC200 disk drive interface */
#include "devices/mflopimg.h"	/* for NC200 disk image */
#include "formats/pc_dsk.h"		/* for NC200 disk image */
#include "includes/serial.h"	/* for serial data transfers */
#include "devices/cartslot.h"
#include "sound/beep.h"

/* uncomment for verbose debugging information */
/* #define VERBOSE */

#define NC200_DEBUG

#include "includes/centroni.h"
#include "devices/printer.h"

/* the serial clock is generated by the nc hardware and connected to the msm8251
receive clock and transmit clock inputs */
static void *nc_serial_timer;

static void nc_printer_update(int);

UINT8 nc_type;

static char nc_memory_config[4];
unsigned long nc_display_memory_start;
static mame_timer *nc_keyboard_timer = NULL;

static int nc_membank_rom_mask;
static int nc_membank_internal_ram_mask;
int nc_membank_card_ram_mask;

/*
	Port 0x00:
	==========

	Display memory start:

	NC100:
			bit 7           A15
			bit 6           A14
			bit 5           A13
			bit 4           A12
			bits 3-0        Not Used
	NC200:
			bit 7           A15
			bit 6           A14
			bit 5           A13
			bits 4-0        Not Used

	Port 0x010-0x013:
	=================

	Memory management control:

	NC100 & NC200:

        10              controls 0000-3FFF
        11              controls 4000-7FFF
        12              controls 8000-BFFF
        13              controls C000-FFFF

	Port 0x030:
	===========

	NC100:
			bit 7     select card register 1=common, 0=attribute
			bit 6     parallel interface Strobe signal
			bit 5     Not Used
			bit 4     uPD4711 line driver, 1=off, 0=on
			bit 3     UART clock and reset, 1=off, 0=on

			bits 2-0  set the baud rate as follows

					000 = 150
					001 = 300
					010 = 600
					011 = 1200
					100 = 2400
					101 = 4800
					110 = 9600
					111 = 19200
	NC200:
			bit 7     select card register 1=common, 0=attribute
			bit 6     parallel interface Strobe signal

			bit 5     used in disc interface; (set to 0)

			bit 4     uPD4711 line driver, 1=off, 0=on
			bit 3     UART clock and reset, 1=off, 0=on

			bits 2-0  set the baud rate as follows

					000 = 150
					001 = 300
					010 = 600
					011 = 1200
					100 = 2400
					101 = 4800
					110 = 9600
					111 = 19200


	Port 0x0a0:
	===========

	NC100:
			bit 7: memory card present 0 = yes, 1 = no
			bit 6: memory card write protected 1 = yes, 0 = no
			bit 5: input voltage = 1, if >= to 4 volts
			bit 4: mem card battery: 0 = battery low
			bit 3: alkaline batteries. 0 if >=3.2 volts
			bit 2: lithium battery 0 if >= 2.7 volts
			bit 1: parallel interface busy (0 if busy)
			bit 0: parallel interface ack (1 if ack)

	NC200:

			bit 7: memory card present 0 = yes, 1 = no
			bit 6: memory card write protected 1 = yes, 0 = no
			bit 5: lithium battery 0 if >= 2.7 volts
			bit 4: input voltage = 1, if >= to 4 volts
			bit 3: ??
			bit 2: alkaline batteries. 0 if >=3.2 volts
			bit 1: ??
			bit 0: battery power: if 1: batteries are too low for disk usage, if 0: batteries ok for disc usage


	Port 0x060 (IRQ MASK), Port 0x090 (IRQ STATUS):
	===============================================

	NC100:
			bit 7: not used
			bit 6: not used
			bit 5: not used
			bit 4: not used
			Bit 3: Key scan interrupt (10ms)
			Bit 2: ACK from parallel interface
			Bit 1: Tx Ready
			Bit 0: Rx Ready

	NC200:
			bit 7: ???
			bit 6: RTC alarm?
			bit 5: FDC interrupt
			bit 4: Power off interrupt
			Bit 3: Key scan interrupt (10ms)
			Bit 2: serial interrupt (tx ready/rx ready combined)
			Bit 1: not used
			Bit 0: ACK from parallel interface

	Port 0x070: On/off control

	NC200:
		bit 7: nc200 power on/off: 1 = on, 0=off
		bit 2: backlight: 1=off, 0=on
		bit 1: disk motor: 1=off, 0=disk motor???
		bit 0: nec765 terminal count input
*/


static UINT8 nc_poweroff_control;

/* this is not a real register, it is used to record card status */
/* ==0, card not inserted, !=0 card is inserted */
static int nc_card_status = 0;

/* set pcmcia card present state */
void nc_set_card_present_state(int state)
{
	nc_card_status = state;
}

/* card ram */
unsigned char *nc_card_ram = NULL;

static unsigned char nc_uart_control;

static int nc_irq_mask;
static int nc_irq_status;


/* latched interrupts are interrupts that cannot be cleared by writing to the irq
mask. latched interrupts can only be cleared by accessing the interrupting
device e.g. serial chip, fdc */
static int nc_irq_latch;
/* this is a mask of irqs that are latched, and it is different for nc100 and
nc200 */
static int nc_irq_latch_mask;
static int nc_sound_channel_periods[2];

static void nc_update_interrupts(void)
{
	nc_irq_status &= ~nc_irq_latch_mask;
	nc_irq_status |= nc_irq_latch;

	/* any ints set and they are not masked? */
	if (
			(((nc_irq_status & nc_irq_mask) & 0x3f)!=0)
			)
	{
		logerror("int set %02x\n",nc_irq_status & nc_irq_mask);
		/* set int */
		cpunum_set_input_line(0,0, HOLD_LINE);
	}
	else
	{
		/* clear int */
		cpunum_set_input_line(0,0, CLEAR_LINE);
	}
}

static void nc_keyboard_timer_callback(int dummy)
{
#ifdef VERBOSE
		logerror("keyboard int\n");
#endif

        /* set int */
        nc_irq_status |= (1<<3);

        /* update ints */
        nc_update_interrupts();

        /* don't trigger again, but don't free it */
        timer_reset(nc_keyboard_timer, TIME_NEVER);
}


static read8_handler nc_bankhandler_r[]={
MRA8_BANK1, MRA8_BANK2, MRA8_BANK3, MRA8_BANK4};

static write8_handler nc_bankhandler_w[]={
MWA8_BANK5, MWA8_BANK6, MWA8_BANK7, MWA8_BANK8};

static void nc_refresh_memory_bank_config(int bank)
{
	int mem_type;
	int mem_bank;
	read8_handler read_handler;
	write8_handler write_handler = NULL;

	mem_type = (nc_memory_config[bank]>>6) & 0x03;
	mem_bank = nc_memory_config[bank] & 0x03f;

	read_handler = nc_bankhandler_r[bank];

	switch (mem_type)
	{
		/* ROM */
		case 3:
		case 0:
		{
			unsigned char *addr;

			mem_bank = mem_bank & nc_membank_rom_mask;

			addr = (memory_region(REGION_CPU1)+0x010000) + (mem_bank<<14);

			memory_set_bankptr(bank+1, addr);

			write_handler = MWA8_NOP;
#ifdef VERBOSE
			logerror("BANK %d: ROM %d\n",bank,mem_bank);
#endif
		}
		break;

		/* internal RAM */
		case 1:
		{
			unsigned char *addr;

			mem_bank = mem_bank & nc_membank_internal_ram_mask;

			addr = mess_ram + (mem_bank<<14);

			memory_set_bankptr(bank+1, addr);
			memory_set_bankptr(bank+5, addr);

			write_handler = nc_bankhandler_w[bank];
#ifdef VERBOSE
			logerror("BANK %d: RAM\n",bank);
#endif
		}
		break;

		/* card RAM */
		case 2:
		{
			/* card connected? */
			if ((nc_card_status) && (nc_card_ram!=NULL))
			{
				unsigned char *addr;

				mem_bank = mem_bank & nc_membank_card_ram_mask;
				addr = nc_card_ram + (mem_bank<<14);

				memory_set_bankptr(bank+1, addr);

				/* write enabled? */
				if (readinputport(10) & 0x02)
				{
					/* yes */
					memory_set_bankptr(bank+5, addr);

					write_handler = nc_bankhandler_w[bank];
				}
				else
				{
					/* no */
					write_handler = MWA8_NOP;
				}

#ifdef VERBOSE
				logerror("BANK %d: CARD-RAM\n",bank);
#endif
			}
			else
			{
				/* if no card connected, then writes fail */
				read_handler = MRA8_NOP;
				write_handler = MWA8_NOP;
			}
		}
		break;
	}

	memory_install_read8_handler(0, ADDRESS_SPACE_PROGRAM,
		(bank * 0x4000), (bank * 0x4000) + 0x3fff, 0, 0, read_handler);

	if (write_handler)
	{
		memory_install_write8_handler(0, ADDRESS_SPACE_PROGRAM,
			(bank * 0x4000), (bank * 0x4000) + 0x3fff, 0, 0, write_handler);
	}
}

static void nc_refresh_memory_config(void)
{
	nc_refresh_memory_bank_config(0);
	nc_refresh_memory_bank_config(1);
	nc_refresh_memory_bank_config(2);
	nc_refresh_memory_bank_config(3);
}


static mame_file *file;

/* restore a block of memory from the nvram file */
static void nc_common_restore_memory_from_stream(void)
{
	unsigned long stored_size;
	unsigned long restore_size;

	if (!file)
		return;

#ifdef VERBOSE
	logerror("restoring nc memory\n");
#endif
	/* get size of memory data stored */
	mame_fread(file, &stored_size, sizeof(unsigned long));

	if (stored_size > mess_ram_size)
		restore_size = mess_ram_size;
	else
		restore_size = stored_size;

	/* read as much as will fit into memory */
	mame_fread(file, mess_ram, restore_size);
	/* seek over remaining data */
	mame_fseek(file, SEEK_CUR,stored_size - restore_size);
}

/* store a block of memory to the nvram file */
static void nc_common_store_memory_to_stream(void)
{
	if (!file)
		return;

#ifdef VERBOSE
	logerror("storing nc memory\n");
#endif
	/* write size of memory data */
	mame_fwrite(file, &mess_ram_size, sizeof(unsigned long));

	/* write data block */
	mame_fwrite(file, mess_ram, mess_ram_size);
}

static void nc_common_open_stream_for_reading(void)
{
	char filename[13];

	sprintf(filename,"%s.nv", Machine->gamedrv->name);

	file = mame_fopen(Machine->gamedrv->name, filename, FILETYPE_MEMCARD, OSD_FOPEN_READ);
}

static void nc_common_open_stream_for_writing(void)
{
    char filename[13];

    sprintf(filename,"%s.nv", Machine->gamedrv->name);

    file = mame_fopen(Machine->gamedrv->name, filename, FILETYPE_MEMCARD, OSD_FOPEN_WRITE);
}


static void	nc_common_close_stream(void)
{
	if (file)
		mame_fclose(file);
}



static int	previous_inputport_10_state;

static void dummy_timer_callback(int dummy)
{
	int inputport_10_state;
	int changed_bits;

    inputport_10_state = readinputport(10);

	changed_bits = inputport_10_state^previous_inputport_10_state;

	/* on/off button changed state? */
	if (changed_bits & 0x01)
	{
        if (inputport_10_state & 0x01)
        {
			/* on NC100 on/off button causes a nmi, on
			nc200 on/off button causes an int */
			switch (nc_type)
			{
				case NC_TYPE_1xx:
				{
#ifdef VERBOSE
			        logerror("nmi triggered\n");
#endif
				    cpunum_set_input_line(0, INPUT_LINE_NMI, PULSE_LINE);
				}
				break;

				case NC_TYPE_200:
				{
					nc_irq_status |=(1<<4);
					nc_update_interrupts();
				}
				break;
			}
        }
	}

	/* memory card write enable/disable state changed? */
	if (changed_bits & 0x02)
	{
		/* yes refresh memory config */
		nc_refresh_memory_config();
	}

	previous_inputport_10_state = inputport_10_state;
}

static void nc_serial_timer_callback(int dummy);

static void nc_common_init_machine(void)
{
	/* setup reset state */
	nc_display_memory_start = 0;

	/* setup reset state */
    nc_memory_config[0] = 0;
    nc_memory_config[1] = 0;
    nc_memory_config[2] = 0;
    nc_memory_config[3] = 0;

	previous_inputport_10_state = readinputport(10);

    /* setup reset state ints are masked */
    nc_irq_mask = 0;
    /* setup reset state no ints wanting servicing */
    nc_irq_status = 0;
    /* at reset set to 0x0ffff */

	nc_irq_latch = 0;
	nc_irq_latch_mask = 0;

	/* setup reset state */
	nc_sound_channel_periods[0] = (nc_sound_channel_periods[1] = 0x0ffff);

    /* at reset set to 1 */
    nc_poweroff_control = 1;

    nc_refresh_memory_config();
	nc_update_interrupts();

	/* keyboard timer */
	nc_keyboard_timer = timer_alloc(nc_keyboard_timer_callback);
	timer_adjust(nc_keyboard_timer, TIME_IN_MSEC(10), 0, 0);

	/* dummy timer */
	timer_pulse(TIME_IN_HZ(50), 0, dummy_timer_callback);

	/* serial timer */
	nc_serial_timer = timer_alloc(nc_serial_timer_callback);

	/* at reset set to 0x0ff */
	nc_uart_control = 0x0ff;
}

static ADDRESS_MAP_START(nc_map, ADDRESS_SPACE_PROGRAM, 8 )
	AM_RANGE(0x0000, 0x3fff) AM_READWRITE(MRA8_BANK1, MWA8_BANK5)
	AM_RANGE(0x4000, 0x7fff) AM_READWRITE(MRA8_BANK2, MWA8_BANK6)
	AM_RANGE(0x8000, 0xbfff) AM_READWRITE(MRA8_BANK3, MWA8_BANK7)
	AM_RANGE(0xc000, 0xffff) AM_READWRITE(MRA8_BANK4, MWA8_BANK8)
ADDRESS_MAP_END


static  READ8_HANDLER(nc_memory_management_r)
{
	return nc_memory_config[offset];
}

static WRITE8_HANDLER(nc_memory_management_w)
{
#ifdef VERBOSE
	logerror("Memory management W: %02x %02x\n",offset,data);
#endif
        nc_memory_config[offset] = data;

        nc_refresh_memory_config();
}

static WRITE8_HANDLER(nc_irq_mask_w)
{
#ifdef VERBOSE
	logerror("irq mask w: %02x\n", data);
#endif
#ifdef NC200_DEBUG
	logerror("irq mask nc200 w: %02x\n",data & ((1<<4) | (1<<5) | (1<<6) | (1<<7)));
#endif

	/* writing mask clears ints that are to be masked? */
	nc_irq_mask = data;

	nc_update_interrupts();
}

static WRITE8_HANDLER(nc_irq_status_w)
{
#ifdef VERBOSE
	logerror("irq status w: %02x\n", data);
#endif
    data = data^0x0ff;

	if (nc_type == NC_TYPE_200)
	{
		/* Russell Marks confirms that on the NC200, the key scan interrupt must be explicitly
		cleared. It is not automatically cleared when reading 0x0b9 */
		if ((data & (1<<3))!=0)
		{
			/* set timer to occur again */
			timer_reset(nc_keyboard_timer, TIME_IN_MSEC(10));

			nc_update_interrupts();
		}
	}


/* writing to status will clear int, will this re-start the key-scan? */
#if 0
        if (
                /* clearing keyboard int? */
                ((data & (1<<3))!=0) &&
                /* keyboard int request? */
                ((nc_irq_status & (1<<3))!=0)
           )
        {
			/* set timer to occur again */
			timer_reset(nc_keyboard_timer, TIME_IN_MSEC(10));
        }
#endif
        nc_irq_status &=~data;

        nc_update_interrupts();
}

static  READ8_HANDLER(nc_irq_status_r)
{
        return ~((nc_irq_status & (~nc_irq_latch_mask)) | nc_irq_latch);
}


static  READ8_HANDLER(nc_key_data_in_r)
{
	if (offset==9)
	{
		/* reading 0x0b9 will clear int and re-start scan procedure! */
		nc_irq_status &= ~(1<<3);

		/* set timer to occur again */
		timer_reset(nc_keyboard_timer, TIME_IN_MSEC(10));

		nc_update_interrupts();
	}
	return readinputport(offset);
}


static void nc_sound_update(int channel)
{
        int on;
        int frequency;
        int period;

        period = nc_sound_channel_periods[channel];

        /* if top bit is 0, sound is on */
        on = ((period & (1<<15))==0);

        /* calculate frequency from period */
        frequency = (int)(1000000.0f/((float)((period & 0x07fff)<<1) * 1.6276f));

        /* set state */
        beep_set_state(channel, on);
        /* set frequency */
        beep_set_frequency(channel, frequency);
}

static WRITE8_HANDLER(nc_sound_w)
{
#ifdef VERBOSE
	logerror("sound w: %04x %02x\n", offset, data);
#endif
	switch (offset)
	{
		case 0x0:
		{
		   /* update period value */
		   nc_sound_channel_periods[0]  =
				(nc_sound_channel_periods[0] & 0x0ff00) | (data & 0x0ff);

		   nc_sound_update(0);
		}
		break;

		case 0x01:
		{
		   nc_sound_channel_periods[0] =
				(nc_sound_channel_periods[0] & 0x0ff) | ((data & 0x0ff)<<8);

		   nc_sound_update(0);
		}
		break;

		case 0x02:
		{
		   /* update period value */
		   nc_sound_channel_periods[1]  =
				(nc_sound_channel_periods[1] & 0x0ff00) | (data & 0x0ff);

		   nc_sound_update(1);
		}
		break;

		case 0x03:
		{
		   nc_sound_channel_periods[1] =
				(nc_sound_channel_periods[1] & 0x0ff) | ((data & 0x0ff)<<8);

		   nc_sound_update(1);
		}
		break;

		default:
		 break;
	}
}

static unsigned long baud_rate_table[]=
{
	150,
    300,
    600,
    1200,
    2400,
    4800,
    9600,
    19200
};

static void nc_serial_timer_callback(int dummy)
{
	msm8251_transmit_clock();
	msm8251_receive_clock();
}

static WRITE8_HANDLER(nc_uart_control_w)
{
	/* update printer state */
	nc_printer_update(data);

	/* on/off changed state? */
	if (((nc_uart_control ^ data) & (1<<3))!=0)
	{
		/* changed uart from off to on */
		if ((data & (1<<3))==0)
		{
			msm8251_reset();
		}
	}

	timer_adjust(nc_serial_timer, 0, 0, TIME_IN_HZ(baud_rate_table[(data & 0x07)]));

	nc_uart_control = data;
}

/* NC100 printer emulation */
/* port 0x040 (write only) = 8-bit printer data */
/* port 0x030 bit 6 = printer strobe */

/* same for nc100 and nc200 */
static WRITE8_HANDLER(nc_printer_data_w)
{
#ifdef VERBOSE
	logerror("printer write %02x\n",data);
#endif
	centronics_write_data(0,data);
}

/* same for nc100 and nc200 */
static void	nc_printer_update(int port0x030)
{
	int handshake = 0;

	if (port0x030 & (1<<6))
	{
		handshake = CENTRONICS_STROBE;
	}
	/* assumption: select is tied low */
	centronics_write_handshake(0, CENTRONICS_SELECT | CENTRONICS_NO_RESET, CENTRONICS_SELECT| CENTRONICS_NO_RESET);
	centronics_write_handshake(0, handshake, CENTRONICS_STROBE);
}

/********************************************************************************************************/
/* NC100 hardware */

static int previous_alarm_state;


static WRITE8_HANDLER(nc100_display_memory_start_w)
{
	/* bit 7: A15 */
	/* bit 6: A14 */
	/* bit 5: A13 */
	/* bit 4: A12 */
	/* bit 3-0: not used */
	nc_display_memory_start = (data & 0x0f0)<<(12-4);

#ifdef VERBOSE
	logerror("disp memory w: %04x\n", (int) nc_display_memory_start);
#endif

}


static WRITE8_HANDLER(nc100_uart_control_w)
{
	nc_uart_control_w(offset,data);

//	/* is this correct?? */
//	if (data & (1<<3))
//	{
//		/* clear latched irq's */
//		nc_irq_latch &= ~3;
//		nc_update_interrupts();
//	}
}


static void	nc100_tc8521_alarm_callback(int state)
{
	/* I'm assuming that the nmi is edge triggered */
	/* a interrupt from the fdc will cause a change in line state, and
	the nmi will be triggered, but when the state changes because the int
	is cleared this will not cause another nmi */
	/* I'll emulate it like this to be sure */

	if (state!=previous_alarm_state)
	{
		if (state)
		{
			/* I'll pulse it because if I used hold-line I'm not sure
			it would clear - to be checked */
			cpunum_set_input_line(0, INPUT_LINE_NMI, PULSE_LINE);
		}
	}

	previous_alarm_state = state;
}

static void nc100_txrdy_callback(int state)
{
	nc_irq_latch &= ~(1<<1);

	/* uart on? */
	if ((nc_uart_control & (1<<3))==0)
	{
		if (state)
		{
//	#ifdef VERBOSE
			logerror("tx ready\n");
//	#endif
			nc_irq_latch |= (1<<1);
		}
	}

	nc_update_interrupts();
}

static void nc100_rxrdy_callback(int state)
{
	nc_irq_latch &= ~(1<<0);

	if ((nc_uart_control & (1<<3))==0)
	{
		if (state)
		{
//#ifdef VERBOSE
			logerror("rx ready\n");
//#endif
			nc_irq_latch |= (1<<0);
		}
	}

	nc_update_interrupts();
}


static struct tc8521_interface nc100_tc8521_interface=
{
	nc100_tc8521_alarm_callback,
};

static struct msm8251_interface nc100_uart_interface=
{
	nc100_txrdy_callback,
	NULL,
	nc100_rxrdy_callback
};

static void nc100_printer_handshake_in(int number, int data, int mask)
{
	nc_irq_status &= ~(1<<2);

	if (mask & CENTRONICS_ACKNOWLEDGE)
	{
		if (data & CENTRONICS_ACKNOWLEDGE)
		{
			nc_irq_status|=(1<<2);
		}
	}
	/* trigger an int if the irq is set */
	nc_update_interrupts();
}

static CENTRONICS_CONFIG nc100_cent_config[1]={
	{
		PRINTER_CENTRONICS,
		nc100_printer_handshake_in
	},
};

static MACHINE_INIT( nc100 )
{
    nc_type = NC_TYPE_1xx;

    /* 256k of rom */
    nc_membank_rom_mask = 0x0f;

    nc_membank_internal_ram_mask = 3;

    nc_membank_card_ram_mask = 0x03f;

    nc_common_init_machine();

	tc8521_init(&nc100_tc8521_interface);

	msm8251_init(&nc100_uart_interface);

	centronics_config(0, nc100_cent_config);
	/* assumption: select is tied low */
	centronics_write_handshake(0, CENTRONICS_SELECT | CENTRONICS_NO_RESET, CENTRONICS_SELECT| CENTRONICS_NO_RESET);

	nc_common_open_stream_for_reading();
	tc8521_load_stream(file);

	nc_common_restore_memory_from_stream();

	nc_common_close_stream();

	/* serial */
	nc_irq_latch_mask = (1<<0) | (1<<1);

}

static MACHINE_STOP( nc100 )
{
	nc_common_open_stream_for_writing();
	tc8521_save_stream(file);
	nc_common_store_memory_to_stream();
	nc_common_close_stream();
}


static WRITE8_HANDLER(nc100_poweroff_control_w)
{
	/* bits 7-1: not used */
	/* bit 0: 1 = no effect, 0 = power off */
	nc_poweroff_control = data;
#ifdef VERBOSE
	logerror("nc poweroff control: %02x\n",data);
#endif
}


/* nc100 version of card/battery status */
static  READ8_HANDLER(nc100_card_battery_status_r)
{
	int nc_card_battery_status = 0x0ff;

	int printer_handshake;

	if (nc_card_status)
	{
		/* card present */
		nc_card_battery_status &=~(1<<7);
	}

	if (readinputport(10) & 0x02)
	{
		/* card write enable */
		nc_card_battery_status &=~(1<<6);
	}


    /* enough power - see bit assignments where
    nc card battery status is defined */
 	nc_card_battery_status |= (1<<5);
	nc_card_battery_status &= ~((1<<2) | (1<<3));


	/* assumption: select is tied low */
	centronics_write_handshake(0, CENTRONICS_SELECT | CENTRONICS_NO_RESET, CENTRONICS_SELECT| CENTRONICS_NO_RESET);

	printer_handshake = centronics_read_handshake(0);

	nc_card_battery_status |=(1<<1);

	/* if printer is not online, it is busy */
	if ((printer_handshake & CENTRONICS_ONLINE)!=0)
	{
		nc_card_battery_status &=~(1<<1);
	}

	nc_card_battery_status &=~(1<<0);
	if (printer_handshake & CENTRONICS_ACKNOWLEDGE)
	{
		nc_card_battery_status |=(1<<0);
	}

    return nc_card_battery_status;
}

static WRITE8_HANDLER(nc100_memory_card_wait_state_w)
{
#ifdef VERBOSE
	logerror("nc100 memory card wait state: %02x\n",data);
#endif
}



static ADDRESS_MAP_START(nc100_io, ADDRESS_SPACE_IO, 8)
	ADDRESS_MAP_FLAGS( AMEF_ABITS(8) )
	ADDRESS_MAP_FLAGS( AMEF_UNMAP(1) )
	AM_RANGE(0x00, 0x0f) AM_WRITE(nc100_display_memory_start_w)
	AM_RANGE(0x10, 0x13) AM_READWRITE(nc_memory_management_r, nc_memory_management_w)
	AM_RANGE(0x20, 0x20) AM_WRITE(nc100_memory_card_wait_state_w)
	AM_RANGE(0x30, 0x30) AM_WRITE(nc100_uart_control_w)
	AM_RANGE(0x40, 0x40) AM_WRITE(nc_printer_data_w)
    AM_RANGE(0x50, 0x53) AM_WRITE(nc_sound_w)
	AM_RANGE(0x60, 0x60) AM_WRITE(nc_irq_mask_w)
	AM_RANGE(0x70, 0x70) AM_WRITE(nc100_poweroff_control_w)
	AM_RANGE(0x90, 0x90) AM_READWRITE(nc_irq_status_r, nc_irq_status_w)
	AM_RANGE(0x91, 0x9f) AM_READ(nc_irq_status_r)
	AM_RANGE(0xa0, 0xaf) AM_READ(nc100_card_battery_status_r)
	AM_RANGE(0xb0, 0xb9) AM_READ(nc_key_data_in_r)
	AM_RANGE(0xc0, 0xc0) AM_READWRITE(msm8251_data_r, msm8251_data_w)
	AM_RANGE(0xc1, 0xc1) AM_READWRITE(msm8251_status_r, msm8251_control_w)
	AM_RANGE(0xd0, 0xdf) AM_READWRITE(tc8521_r, tc8521_w)
ADDRESS_MAP_END



INPUT_PORTS_START(nc100)
	/* 0 */
	PORT_START
	PORT_BIT(0x001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("LEFT SHIFT") PORT_CODE(KEYCODE_LSHIFT)
	PORT_BIT(0x002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("RIGHT SHIFT") PORT_CODE(KEYCODE_RSHIFT)
	PORT_BIT (0x004, 0x00, IPT_UNUSED)
	PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("LEFT/RED") PORT_CODE(KEYCODE_LEFT)
	PORT_BIT(0x010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("RETURN") PORT_CODE(KEYCODE_ENTER)
	PORT_BIT (0x020, 0x00, IPT_UNUSED)
	PORT_BIT (0x040, 0x00, IPT_UNUSED)
	PORT_BIT (0x080, 0x00, IPT_UNUSED)
	/* 1 */
	PORT_START
	PORT_BIT(0x001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("YELLOW/FUNCTION") PORT_CODE(KEYCODE_RALT)
	PORT_BIT(0x002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("CONTROL") PORT_CODE(KEYCODE_LCONTROL)
	PORT_BIT(0x002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("CONTROL") PORT_CODE(KEYCODE_RCONTROL)
	PORT_BIT(0x004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("ESCAPE/STOP") PORT_CODE(KEYCODE_ESC)
	PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("SPACE") PORT_CODE(KEYCODE_SPACE)
	PORT_BIT (0x010, 0x00, IPT_UNUSED)
	PORT_BIT (0x020, 0x00, IPT_UNUSED)
	PORT_BIT(0x040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("5 %") PORT_CODE(KEYCODE_5)
	PORT_BIT (0x080, 0x00, IPT_UNUSED)
	/* 2 */
	PORT_START
	PORT_BIT(0x001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("ALT") PORT_CODE(KEYCODE_LALT)
	PORT_BIT(0x002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("SYMBOL") PORT_CODE(KEYCODE_HOME)
	PORT_BIT(0x004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("1 !") PORT_CODE(KEYCODE_1)
	PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("TAB") PORT_CODE(KEYCODE_TAB)
	PORT_BIT (0x010, 0x00, IPT_UNUSED)
	PORT_BIT (0x020, 0x00, IPT_UNUSED)
	PORT_BIT (0x040, 0x00, IPT_UNUSED)
	PORT_BIT (0x080, 0x00, IPT_UNUSED)
	/* 3 */
	PORT_START
	PORT_BIT(0x001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("3") PORT_CODE(KEYCODE_3)
	PORT_BIT(0x002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("2 \"") PORT_CODE(KEYCODE_2)
	PORT_BIT(0x004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Q") PORT_CODE(KEYCODE_Q)
	PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("W") PORT_CODE(KEYCODE_W)
	PORT_BIT(0x010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("E") PORT_CODE(KEYCODE_E)
	PORT_BIT (0x020, 0x00, IPT_UNUSED)
	PORT_BIT(0x040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("S") PORT_CODE(KEYCODE_S)
	PORT_BIT(0x080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("D") PORT_CODE(KEYCODE_D)
	/* 4 */
	PORT_START
	PORT_BIT(0x001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("4 $") PORT_CODE(KEYCODE_4)
	PORT_BIT (0x002, 0x00, IPT_UNUSED)
	PORT_BIT(0x004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Z") PORT_CODE(KEYCODE_Z)
	PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("X") PORT_CODE(KEYCODE_X)
	PORT_BIT(0x010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("A") PORT_CODE(KEYCODE_A)
	PORT_BIT (0x020, 0x00, IPT_UNUSED)
	PORT_BIT(0x040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("R") PORT_CODE(KEYCODE_R)
	PORT_BIT(0x080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F") PORT_CODE(KEYCODE_F)
	/* 5 */
	PORT_START
	PORT_BIT (0x001, 0x00, IPT_UNUSED)
	PORT_BIT (0x002, 0x00, IPT_UNUSED)
	PORT_BIT(0x004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("B") PORT_CODE(KEYCODE_B)
	PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("V") PORT_CODE(KEYCODE_V)
	PORT_BIT(0x010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("T") PORT_CODE(KEYCODE_T)
	PORT_BIT(0x020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Y") PORT_CODE(KEYCODE_Y)
	PORT_BIT(0x040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("G") PORT_CODE(KEYCODE_G)
	PORT_BIT(0x080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("C") PORT_CODE(KEYCODE_C)
	/* 6 */
	PORT_START
	PORT_BIT(0x001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("6 ^") PORT_CODE(KEYCODE_6)
	PORT_BIT(0x002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("DOWN/BLUE") PORT_CODE(KEYCODE_DOWN)
	PORT_BIT (0x004, 0x00, IPT_UNUSED)
	PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("RIGHT/GREEN") PORT_CODE(KEYCODE_RIGHT)
	PORT_BIT(0x010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("#") PORT_CODE(KEYCODE_TILDE)
	PORT_BIT(0x020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("?") PORT_CODE(KEYCODE_SLASH)
	PORT_BIT(0x040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("H") PORT_CODE(KEYCODE_H)
	PORT_BIT(0x080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("N") PORT_CODE(KEYCODE_N)
	/* 7 */
	PORT_START
	PORT_BIT(0x001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("+ =") PORT_CODE(KEYCODE_EQUALS)
	PORT_BIT(0x002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("7 &") PORT_CODE(KEYCODE_7)
	PORT_BIT(0x004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("/ |") PORT_CODE(KEYCODE_BACKSLASH)
	PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("UP") PORT_CODE(KEYCODE_UP)
	PORT_BIT(0x010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("MENU") PORT_CODE(KEYCODE_PGUP)
	PORT_BIT(0x020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("U") PORT_CODE(KEYCODE_U)
	PORT_BIT(0x040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("M") PORT_CODE(KEYCODE_M)
	PORT_BIT(0x080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("K") PORT_CODE(KEYCODE_K)
	/* 8 */
	PORT_START
	PORT_BIT(0x001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("8 *") PORT_CODE(KEYCODE_8)
	PORT_BIT(0x002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("- _") PORT_CODE(KEYCODE_MINUS)
	PORT_BIT(0x004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("} ]") PORT_CODE(KEYCODE_CLOSEBRACE)
	PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("{ [") PORT_CODE(KEYCODE_OPENBRACE)
	PORT_BIT(0x010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("@") PORT_CODE(KEYCODE_QUOTE)
	PORT_BIT(0x020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("I") PORT_CODE(KEYCODE_I)
	PORT_BIT(0x040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("J") PORT_CODE(KEYCODE_J)
	PORT_BIT(0x080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME(",") PORT_CODE(KEYCODE_COMMA)
	/* 9 */
	PORT_START
	PORT_BIT(0x001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("0 )") PORT_CODE(KEYCODE_0)
	PORT_BIT(0x002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("9 (") PORT_CODE(KEYCODE_9)
	PORT_BIT(0x004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("DEL") PORT_CODE(KEYCODE_BACKSPACE)
	PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("P") PORT_CODE(KEYCODE_P)
	PORT_BIT(0x010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME(": ;") PORT_CODE(KEYCODE_COLON)
	PORT_BIT(0x020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("L") PORT_CODE(KEYCODE_L)
	PORT_BIT(0x040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("O") PORT_CODE(KEYCODE_O)
	PORT_BIT(0x080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME(".") PORT_CODE(KEYCODE_STOP)

	/* these are not part of the nc100 keyboard */
	/* extra */
	PORT_START
	PORT_BIT(0x001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("ON BUTTON") PORT_CODE(KEYCODE_END)
	/* pcmcia memory card setting */
	PORT_DIPNAME(0x002, 0x002, "PCMCIA Memory card write enable")
	PORT_DIPSETTING(0x000, DEF_STR( Off) )
	PORT_DIPSETTING(0x002, DEF_STR( On) )
INPUT_PORTS_END

/**********************************************************************************************************/
/* NC150 hardware */
/* to be completed! */

#if 0
void nc150_init_machine(void)
{
        nc_membank_internal_ram_mask = 7;

        nc_membank_card_ram_mask = 0x03f;

        nc_common_init_machine();
}
#endif



/**********************************************************************************************************/
/* NC200 hardware */


static WRITE8_HANDLER(nc200_display_memory_start_w)
{
	/* bit 7: A15 */
	/* bit 6: A14 */
	/* bit 5: A13 */
	/* bit 4-0: not used */
	nc_display_memory_start = (data & 0x0e0)<<(12-4);

#ifdef VERBOSE
	logerror("disp memory w: %04x\n", (int) nc_display_memory_start);
#endif

}

static void nc200_printer_handshake_in(int number, int data, int mask)
{
	nc_irq_status &= ~(1<<0);

	if (mask & CENTRONICS_ACKNOWLEDGE)
	{
		if (data & CENTRONICS_ACKNOWLEDGE)
		{
			nc_irq_status|=(1<<0);
		}
	}
	/* trigger an int if the irq is set */
	nc_update_interrupts();
}

static CENTRONICS_CONFIG nc200_cent_config[1]={
	{
		PRINTER_CENTRONICS,
		nc200_printer_handshake_in
	},
};



/* assumption. nc200 uses the same uart chip. The rxrdy and txrdy are combined
together with a or to generate a single interrupt */
static UINT8 nc200_uart_interrupt_irq;

static void nc200_refresh_uart_interrupt(void)
{
	nc_irq_latch &=~(1<<2);

	/* uart enabled? */
	if ((nc_uart_control & (1<<3))==0)
	{
		if ((nc200_uart_interrupt_irq & 0x03)!=0)
		{
			nc_irq_latch |= (1<<2);
		}
	}
	nc_update_interrupts();
}

static void nc200_txrdy_callback(int state)
{
//	nc200_uart_interrupt_irq &=~(1<<0);
//
//	if (state)
//	{
//		nc200_uart_interrupt_irq |=(1<<0);
//	}
//
//	nc200_refresh_uart_interrupt();
}

static void nc200_rxrdy_callback(int state)
{
	nc200_uart_interrupt_irq &=~(1<<1);

	if (state)
	{
		nc200_uart_interrupt_irq |=(1<<1);
	}

	nc200_refresh_uart_interrupt();
}

static struct msm8251_interface nc200_uart_interface=
{
	nc200_rxrdy_callback,
	NULL,
	nc200_txrdy_callback,
};


static void nc200_fdc_interrupt(int state)
{
#if 0
    nc_irq_latch &=~(1<<5);

    if (state)
    {
            nc_irq_latch |=(1<<5);
    }
#endif
    nc_irq_status &=~(1<<5);

    if (state)
    {
            nc_irq_status |=(1<<5);
    }

    nc_update_interrupts();
}

static struct nec765_interface nc200_nec765_interface=
{
    nc200_fdc_interrupt,
    NULL,
};

static void nc200_floppy_drive_index_callback(int drive_id)
{
#ifdef NC200_DEBUG
	logerror("nc200 index pulse\n");
#endif
//	nc_irq_status |= (1<<4);

//	nc_update_interrupts();
}

static MACHINE_INIT( nc200 )
{
    nc_type = NC_TYPE_200;

	/* 512k of rom */
	nc_membank_rom_mask = 0x1f;

    nc_membank_internal_ram_mask = 7;

    nc_membank_card_ram_mask = 0x03f;

    nc_common_init_machine();

    nec765_init(&nc200_nec765_interface, NEC765A);
    /* double sided, 80 track drive */
	floppy_drive_set_geometry(image_from_devtype_and_index(IO_FLOPPY, 0), FLOPPY_DRIVE_DS_80);
	//floppy_drive_set_index_pulse_callback(image_from_devtype_and_index(IO_FLOPPY, 0), nc200_floppy_drive_index_callback);

	mc146818_init(MC146818_STANDARD);

	nc200_uart_interrupt_irq = 0;
	msm8251_init(&nc200_uart_interface);

	centronics_config(0, nc200_cent_config);
	/* assumption: select is tied low */
	centronics_write_handshake(0, CENTRONICS_SELECT | CENTRONICS_NO_RESET, CENTRONICS_SELECT| CENTRONICS_NO_RESET);

	nc_common_open_stream_for_reading();
	if (file)
	{
		mc146818_load_stream(file);
	}
	nc_common_restore_memory_from_stream();
	nc_common_close_stream();

	/* fdc, serial */
	nc_irq_latch_mask = /*(1<<5) |*/ (1<<2);

	nc200_video_set_backlight(0);
}

static MACHINE_STOP( nc200 )
{
	nc_common_open_stream_for_writing();
	if (file)
	{
		mc146818_save_stream(file);
	}
	nc_common_store_memory_to_stream();
	nc_common_close_stream();
}

/*
NC200:

		bit 7: memory card present 0 = yes, 1 = no
		bit 6: memory card write protected 1=yes 0=no
		bit 5: lithium battery 0 if >= 2.7 volts
		bit 4: input voltage = 1, if >= to 4 volts
		bit 3: ??
		bit 2: alkaline batteries. 0 if >=3.2 volts
		bit 1: ??
		bit 0: battery power: if 1: batteries are too low for disk usage, if 0: batteries ok for disc usage
*/


/* nc200 version of card/battery status */
static  READ8_HANDLER(nc200_card_battery_status_r)
{
	int nc_card_battery_status = 0x0ff;

	/* enough power */

	/* input voltage ok */
	nc_card_battery_status |=(1<<4);
	/* lithium batteries and alkaline batteries have enough power,
	and there is enough power for disk usage */
	nc_card_battery_status &=~((1<<5) | (1<<2) | (1<<0));

	if (nc_card_status)
	{
		/* card present */
		nc_card_battery_status&=~(1<<7);
	}

	if (readinputport(10) & 0x02)
	{
		/* card write enable */
		nc_card_battery_status &=~(1<<6);
	}

	return nc_card_battery_status;
}


/* port &80:

  bit 0: Parallel interface BUSY
 */

static  READ8_HANDLER(nc200_printer_status_r)
{
	unsigned char nc200_printer_status = 0x0ff;

	int printer_handshake;

	/* assumption: select is tied low */
	centronics_write_handshake(0, CENTRONICS_SELECT | CENTRONICS_NO_RESET, CENTRONICS_SELECT| CENTRONICS_NO_RESET);

	printer_handshake = centronics_read_handshake(0);

	nc200_printer_status |=(1<<0);

	/* if printer is not online, it is busy */
	if ((printer_handshake & CENTRONICS_ONLINE)!=0)
	{
		nc200_printer_status &=~(1<<0);
	}

    return nc200_printer_status;
}


static WRITE8_HANDLER(nc200_uart_control_w)
{
	int reset_fdc;

	reset_fdc = (nc_uart_control^data) & (1<<5);

	nc_uart_control_w(offset,data);

	if (data & (1<<3))
	{
		nc200_uart_interrupt_irq &=~3;

		nc200_refresh_uart_interrupt();
	}

	/* bit 5 is used in disk interface */
#ifdef NC200_DEBUG
	logerror("bit 5: PC: %04x %02x\n",activecpu_get_pc(), data & (1<<5));
#endif
}


/* bit 7: same as nc100 */
/* bit 2: ?? */
/* bit 1: ?? */
/* %10000110 = 0x086 */
/* %10000010 = 0x082 */
/* %10000011 = 0x083 */
/* writes 86,82 */

/* bit 7: nc200 power control: 1=on, 0=off */
/* bit 1: disk motor??  */
/* bit 0: NEC765 Terminal Count input */

static WRITE8_HANDLER(nc200_memory_card_wait_state_w)
{
#ifdef NC200_DEBUG
	logerror("nc200 memory card wait state: PC: %04x %02x\n",activecpu_get_pc(),data);
#endif
	floppy_drive_set_motor_state(0,1);
	floppy_drive_set_ready_state(0,1,1);

	nec765_set_tc_state((data & 0x01));
}

/* bit 2: backlight: 1=off, 0=on */
/* bit 1 cleared to zero in disk code */
/* bit 0 seems to be the same as nc100 */
static WRITE8_HANDLER(nc200_poweroff_control_w)
{
#ifdef NC200_DEBUG
	logerror("nc200 power off: PC: %04x %02x\n", activecpu_get_pc(),data);
#endif

	nc200_video_set_backlight(((data^(1<<2))>>2) & 0x01);
}

static ADDRESS_MAP_START(nc200_io, ADDRESS_SPACE_IO, 8)
	ADDRESS_MAP_FLAGS( AMEF_ABITS(8) )
	AM_RANGE(0x00, 0x0f) AM_WRITE(nc100_display_memory_start_w)
	AM_RANGE(0x10, 0x13) AM_READWRITE(nc_memory_management_r, nc_memory_management_w)
	AM_RANGE(0x20, 0x20) AM_WRITE(nc200_memory_card_wait_state_w)
	AM_RANGE(0x30, 0x30) AM_WRITE(nc200_uart_control_w)
	AM_RANGE(0x40, 0x40) AM_WRITE(nc_printer_data_w)
    AM_RANGE(0x50, 0x53) AM_WRITE(nc_sound_w)
	AM_RANGE(0x60, 0x60) AM_WRITE(nc_irq_mask_w)
	AM_RANGE(0x70, 0x70) AM_WRITE(nc200_poweroff_control_w)
	AM_RANGE(0x80, 0x80) AM_READ(nc200_printer_status_r)
	AM_RANGE(0x90, 0x90) AM_READWRITE(nc_irq_status_r, nc_irq_status_w)
	AM_RANGE(0xa0, 0xa0) AM_READ(nc200_card_battery_status_r)
	AM_RANGE(0xb0, 0xb9) AM_READ(nc_key_data_in_r)
	AM_RANGE(0xc0, 0xc0) AM_READWRITE(msm8251_data_r, msm8251_data_w)
	AM_RANGE(0xc1, 0xc1) AM_READWRITE(msm8251_status_r, msm8251_control_w)
	AM_RANGE(0xd0, 0xd1) AM_READWRITE(mc146818_port_r, mc146818_port_w)
	AM_RANGE(0xe0, 0xe0) AM_READ(nec765_status_r)
	AM_RANGE(0xe1, 0xe1) AM_READWRITE(nec765_data_r, nec765_data_w)
ADDRESS_MAP_END


INPUT_PORTS_START(nc200)
	/* 0 */
	PORT_START
	PORT_BIT(0x001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("LEFT SHIFT") PORT_CODE(KEYCODE_LSHIFT)
	PORT_BIT(0x002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("RIGHT SHIFT") PORT_CODE(KEYCODE_RSHIFT)
	PORT_BIT(0x004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("4 $") PORT_CODE(KEYCODE_4)
	PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("LEFT/RED") PORT_CODE(KEYCODE_LEFT)
	PORT_BIT(0x010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("RETURN") PORT_CODE(KEYCODE_ENTER)
	PORT_BIT (0x020, 0x00, IPT_UNUSED)
	PORT_BIT (0x040, 0x00, IPT_UNUSED)
	PORT_BIT (0x080, 0x00, IPT_UNUSED)
	/* 1 */
	PORT_START
	PORT_BIT(0x001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("YELLOW/FUNCTION") PORT_CODE(KEYCODE_RALT)
	PORT_BIT(0x002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("CONTROL") PORT_CODE(KEYCODE_LCONTROL)
	PORT_BIT(0x002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("CONTROL") PORT_CODE(KEYCODE_RCONTROL)
	PORT_BIT(0x004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("ESCAPE/STOP") PORT_CODE(KEYCODE_ESC)
	PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("SPACE") PORT_CODE(KEYCODE_SPACE)
	PORT_BIT (0x010, 0x00, IPT_UNUSED)
	PORT_BIT (0x020, 0x00, IPT_UNUSED)
	PORT_BIT (0x040, 0x00, IPT_UNUSED)
	PORT_BIT(0x080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("9 (") PORT_CODE(KEYCODE_9)
	/* 2 */
	PORT_START
	PORT_BIT(0x001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("ALT") PORT_CODE(KEYCODE_LALT)
	PORT_BIT(0x002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("SYMBOL") PORT_CODE(KEYCODE_HOME)
	PORT_BIT(0x004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("1 !") PORT_CODE(KEYCODE_1)
	PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("TAB") PORT_CODE(KEYCODE_TAB)
	PORT_BIT(0x010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("5") PORT_CODE(KEYCODE_5)
	PORT_BIT (0x020, 0x00, IPT_UNUSED)
	PORT_BIT(0x040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("6 ^") PORT_CODE(KEYCODE_6)
	PORT_BIT (0x080, 0x00, IPT_UNUSED)
	/* 3 */
	PORT_START
	PORT_BIT(0x001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("3") PORT_CODE(KEYCODE_3)
	PORT_BIT(0x002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("2 \"") PORT_CODE(KEYCODE_2)
	PORT_BIT(0x004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Q") PORT_CODE(KEYCODE_Q)
	PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("W") PORT_CODE(KEYCODE_W)
	PORT_BIT(0x010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("E") PORT_CODE(KEYCODE_E)
	PORT_BIT (0x020, 0x00, IPT_UNUSED)
	PORT_BIT(0x040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("S") PORT_CODE(KEYCODE_S)
	PORT_BIT(0x080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("D") PORT_CODE(KEYCODE_D)
	/* 4 */
	PORT_START
	PORT_BIT(0x001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("8 *") PORT_CODE(KEYCODE_8)
	PORT_BIT(0x002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("7 &") PORT_CODE(KEYCODE_7)
	PORT_BIT(0x004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Z") PORT_CODE(KEYCODE_Z)
	PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("X") PORT_CODE(KEYCODE_X)
	PORT_BIT(0x010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("A") PORT_CODE(KEYCODE_A)
	PORT_BIT (0x020, 0x00, IPT_UNUSED)
	PORT_BIT(0x040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("R") PORT_CODE(KEYCODE_R)
	PORT_BIT(0x080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("F") PORT_CODE(KEYCODE_F)
	/* 5 */
	PORT_START
	PORT_BIT (0x001, 0x00, IPT_UNUSED)
	PORT_BIT (0x002, 0x00, IPT_UNUSED)
	PORT_BIT(0x004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("B") PORT_CODE(KEYCODE_B)
	PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("V") PORT_CODE(KEYCODE_V)
	PORT_BIT(0x010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("T") PORT_CODE(KEYCODE_T)
	PORT_BIT(0x020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("Y") PORT_CODE(KEYCODE_Y)
	PORT_BIT(0x040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("G") PORT_CODE(KEYCODE_G)
	PORT_BIT(0x080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("C") PORT_CODE(KEYCODE_C)
	/* 6 */
	PORT_START
	PORT_BIT (0x001, 0x00, IPT_UNUSED)
	PORT_BIT(0x002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("DOWN/BLUE") PORT_CODE(KEYCODE_DOWN)
	PORT_BIT (0x004, 0x00, IPT_UNUSED)
	PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("RIGHT/GREEN") PORT_CODE(KEYCODE_RIGHT)
	PORT_BIT(0x010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("#") PORT_CODE(KEYCODE_TILDE)
	PORT_BIT(0x020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("?") PORT_CODE(KEYCODE_SLASH)
	PORT_BIT(0x040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("H") PORT_CODE(KEYCODE_H)
	PORT_BIT(0x080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("N") PORT_CODE(KEYCODE_N)
	/* 7 */
	PORT_START
	PORT_BIT (0x001, 0x00, IPT_UNUSED)
	PORT_BIT(0x002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("+ = ") PORT_CODE(KEYCODE_EQUALS)
	PORT_BIT(0x004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("/ |") PORT_CODE(KEYCODE_BACKSLASH)
	PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("UP") PORT_CODE(KEYCODE_UP)
	PORT_BIT(0x010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("MENU") PORT_CODE(KEYCODE_PGUP)
	PORT_BIT(0x020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("U") PORT_CODE(KEYCODE_U)
	PORT_BIT(0x040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("M") PORT_CODE(KEYCODE_M)
	PORT_BIT(0x080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("K") PORT_CODE(KEYCODE_K)
	/* 8 */
	PORT_START
	PORT_BIT (0x001, 0x00, IPT_UNUSED)
	PORT_BIT(0x002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("- _") PORT_CODE(KEYCODE_MINUS)
	PORT_BIT(0x004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("} ]") PORT_CODE(KEYCODE_CLOSEBRACE)
	PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("{ [") PORT_CODE(KEYCODE_OPENBRACE)
	PORT_BIT(0x010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("@") PORT_CODE(KEYCODE_QUOTE)
	PORT_BIT(0x020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("I") PORT_CODE(KEYCODE_I)
	PORT_BIT(0x040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("J") PORT_CODE(KEYCODE_J)
	PORT_BIT(0x080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME(",") PORT_CODE(KEYCODE_COMMA)
	/* 9 */
	PORT_START
	PORT_BIT (0x001, 0x00, IPT_UNUSED)
	PORT_BIT(0x002, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("0 )") PORT_CODE(KEYCODE_0)
	PORT_BIT(0x004, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("DEL") PORT_CODE(KEYCODE_BACKSPACE)
	PORT_BIT(0x008, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("P") PORT_CODE(KEYCODE_P)
	PORT_BIT(0x010, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME(": ;") PORT_CODE(KEYCODE_COLON)
	PORT_BIT(0x020, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("L") PORT_CODE(KEYCODE_L)
	PORT_BIT(0x040, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("O") PORT_CODE(KEYCODE_O)
	PORT_BIT(0x080, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME(".") PORT_CODE(KEYCODE_STOP)

	/* not part of the nc200 keyboard */
	PORT_START
	PORT_BIT(0x001, IP_ACTIVE_HIGH, IPT_KEYBOARD) PORT_NAME("ON BUTTON") PORT_CODE(KEYCODE_END)
	/* pcmcia memory card setting */
	PORT_DIPNAME(0x002, 0x002, "PCMCIA Memory card write enable")
	PORT_DIPSETTING(0x000, DEF_STR( Off) )
	PORT_DIPSETTING(0x002, DEF_STR( On) )
INPUT_PORTS_END


/**********************************************************************************************************/



static MACHINE_DRIVER_START( nc100 )
	/* basic machine hardware */
	MDRV_CPU_ADD_TAG("main", Z80, /*6000000*/ 4606000)        /* Russell Marks says this is more accurate */
	MDRV_CPU_PROGRAM_MAP(nc_map, 0)
	MDRV_CPU_IO_MAP(nc100_io, 0)
	MDRV_FRAMES_PER_SECOND(50)
	MDRV_VBLANK_DURATION(DEFAULT_REAL_60HZ_VBLANK_DURATION)
	MDRV_INTERLEAVE(1)

	MDRV_MACHINE_INIT( nc100 )
	MDRV_MACHINE_STOP( nc100 )

    /* video hardware */
	MDRV_VIDEO_ATTRIBUTES(VIDEO_TYPE_RASTER)
	MDRV_SCREEN_SIZE(640 /*NC_SCREEN_WIDTH*/, 480 /*NC_SCREEN_HEIGHT*/)
	MDRV_VISIBLE_AREA(0, 640-1, 0, 480-1)
	MDRV_PALETTE_LENGTH(NC_NUM_COLOURS)
	MDRV_COLORTABLE_LENGTH(NC_NUM_COLOURS)
	MDRV_PALETTE_INIT( nc )

	MDRV_VIDEO_START( nc )
	MDRV_VIDEO_UPDATE( nc )

	/* sound hardware */
	MDRV_SPEAKER_STANDARD_MONO("mono")
	MDRV_SOUND_ADD(BEEP, 0)
	MDRV_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50)
	MDRV_SOUND_ADD(BEEP, 0)
	MDRV_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50)
MACHINE_DRIVER_END


static MACHINE_DRIVER_START( nc200 )
	MDRV_IMPORT_FROM( nc100 )
	MDRV_CPU_MODIFY( "main" )
	MDRV_CPU_IO_MAP(nc200_io, 0)

	MDRV_MACHINE_INIT( nc200 )
	MDRV_MACHINE_STOP( nc200 )

    /* video hardware */
	MDRV_SCREEN_SIZE(NC200_SCREEN_WIDTH, NC200_SCREEN_HEIGHT)
	MDRV_VISIBLE_AREA(0, NC200_SCREEN_WIDTH-1, 0, NC200_SCREEN_HEIGHT-1)
	MDRV_PALETTE_LENGTH(NC200_NUM_COLOURS)
	MDRV_COLORTABLE_LENGTH(NC200_NUM_COLOURS)
MACHINE_DRIVER_END


/***************************************************************************

  Game driver(s)

***************************************************************************/

ROM_START(nc100)
	ROM_REGION(((64*1024)+(256*1024)), REGION_CPU1,0)
	ROM_LOAD("nc100.rom", 0x010000, 0x040000, CRC(a699eca3) SHA1(ce217d5a298b959ccc3d7bc5c93b1dba043f1339))
ROM_END

ROM_START(nc100a)
        ROM_REGION(((64*1024)+(256*1024)), REGION_CPU1,0)
        ROM_LOAD("nc100a.rom", 0x010000, 0x040000, CRC(849884f9) SHA1(ff030dd334ca867d620ee4a94b142ef0d93b69b6))
ROM_END

ROM_START(nc200)
        ROM_REGION(((64*1024)+(512*1024)), REGION_CPU1,0)
        ROM_LOAD("nc200.rom", 0x010000, 0x080000, CRC(bb8180e7) SHA1(fb5c93b0a3e199202c6a12548d2617f7a09bae47))
ROM_END

static void nc_common_printer_getinfo(struct IODevice *dev)
{
	/* printer */
	printer_device_getinfo(dev);
	dev->count = 1;
}

static void nc_common_cartslot_getinfo(struct IODevice *dev)
{
	/* cartslot */
	cartslot_device_getinfo(dev);
	dev->count = 1;
	dev->file_extensions = "crd\0card\0";
	dev->init = device_init_nc_pcmcia_card;
	dev->load = device_load_nc_pcmcia_card;
	dev->unload = device_unload_nc_pcmcia_card;
}

static void nc_common_serial_getinfo(struct IODevice *dev)
{
	/* serial */
	dev->type = IO_SERIAL;
	dev->count = 1;
	dev->file_extensions = "txt\0";
	dev->readable = 1;
	dev->writeable = 0;
	dev->creatable = 0;
	dev->init = serial_device_init;
	dev->load = device_load_nc_serial;
	dev->unload = serial_device_unload;
}

SYSTEM_CONFIG_START(nc_common)
	CONFIG_DEVICE(nc_common_printer_getinfo)
	CONFIG_DEVICE(nc_common_cartslot_getinfo)
	CONFIG_DEVICE(nc_common_serial_getinfo)
SYSTEM_CONFIG_END

SYSTEM_CONFIG_START(nc100)
	CONFIG_IMPORT_FROM(nc_common)
	CONFIG_RAM_DEFAULT(64 * 1024)
SYSTEM_CONFIG_END

static void nc200_floppy_getinfo(struct IODevice *dev)
{
	/* floppy */
	floppy_device_getinfo(dev, floppyoptions_pc);
	dev->count = 1;
}

SYSTEM_CONFIG_START(nc200)
	CONFIG_IMPORT_FROM(nc_common)
	CONFIG_RAM_DEFAULT(128 * 1024)
	CONFIG_DEVICE(nc200_floppy_getinfo)
SYSTEM_CONFIG_END

/*    YEAR  NAME       PARENT  COMPAT	MACHINE    INPUT     INIT     CONFIG,  COMPANY               FULLNAME */
COMP( 1992, nc100,     0,      0,		nc100,     nc100,    0,       nc100,   "Amstrad plc", "NC100")
COMP( 1992, nc100a,    nc100,  0,		nc100,     nc100,    0,       nc100,   "Amstrad plc", "NC100 (Version 1.09)")
COMP( 1993, nc200,     0,      0,		nc200,     nc200,    0,       nc200,   "Amstrad plc", "NC200")
