#include "includes/newbrain.h"

/*

    NewBrain
    Grundy Business Systems Ltd.

    32K RAM
    28K ROM

    Z80 @ 2MHz
    COP420 @ 2MHz

    Z80 @ 4MHz (416): INT/NMI=+5V, WAIT=EXTBUSRQ|BUSAKD, RESET=_FDC RESET,
    NEC 765AC @ 4 MHz (418)
    MC6850 ACIA (459)
    Z80CTC (458)
    ADC0809 (427)
    DAC0808 (461)

    Models according to the Software Technical Manual:

    Model M: 'Page Register', Expansion Port onto Z80 bus, Video, ACIA/CTC, User Port
    Model A: Expansion Port, Video, no User Port but has software driver serial port - s/w Printer, s/w V24
    Model V: ACIA/CTC, User Port

*/

/*

    TODO:

    - bitmapped graphics mode
    - COP420 microbus access
    - escape key is missing
    - CP/M 2.2 ROMs
    - floppy disc controller
    - convert FDC into a device
    - convert EIM into a device

    - Micropage ROM/RAM card
    - Z80 PIO board
    - peripheral (PI) box
    - sound card

*/

void newbrain_state::check_interrupt()
{
	int level = (!m_clkint || !m_copint) ? ASSERT_LINE : CLEAR_LINE;

	m_maincpu->set_input_line(INPUT_LINE_IRQ0, level);
}

/* Bank Switching */

#define memory_install_unmapped(program, bank, bank_start, bank_end) \
	program->unmap_readwrite(bank_start, bank_end);

#define memory_install_rom_helper(program, bank, bank_start, bank_end) \
	program->install_read_bank(bank_start, bank_end, bank); \
	program->unmap_write(bank_start, bank_end);

#define memory_install_ram_helper(program, bank, bank_start, bank_end) \
	program->install_readwrite_bank(bank_start, bank_end, bank);

void newbrain_eim_state::bankswitch()
{
	address_space *program = m_maincpu->memory().space(AS_PROGRAM);
	int bank;

	for (bank = 1; bank < 9; bank++)
	{
		int page = (m_a16 << 3) | bank;
		UINT8 data = ~m_pr[page];
		int ch = (data >> 3) & 0x03;
		int eim_bank = data & 0x07;

		UINT16 eim_bank_start = eim_bank * 0x2000;
		UINT16 bank_start = (bank - 1) * 0x2000;
		UINT16 bank_end = bank_start + 0x1fff;
		char bank_name[10];
		sprintf(bank_name,"bank%d",bank);
		switch (ch)
		{
		case 0:
			/* ROM */
			memory_install_rom_helper(program, bank_name, bank_start, bank_end);
			memory_configure_bank(machine(), bank_name, 0, 1, machine().region("eim")->base() + eim_bank_start, 0);
			break;

		case 2:
			/* RAM */
			memory_install_ram_helper(program, bank_name, bank_start, bank_end);
			memory_configure_bank(machine(), bank_name, 0, 1, m_eim_ram + eim_bank_start, 0);
			break;

		default:
			logerror("Invalid memory channel %u!\n", ch);
			break;
		}
	}
}

void newbrain_state::bankswitch()
{
	address_space *program = m_maincpu->memory().space(AS_PROGRAM);
	int bank;

	for (bank = 1; bank < 9; bank++)
	{
		UINT16 bank_start = (bank - 1) * 0x2000;
		UINT16 bank_end = bank_start + 0x1fff;
		char bank_name[10];
		sprintf(bank_name,"bank%d",bank);

		if (m_pwrup)
		{
			/* all banks point to ROM at 0xe000 */
			memory_install_rom_helper(program, bank_name, bank_start, bank_end);
			memory_configure_bank(machine(), bank_name, 0, 1, machine().region(Z80_TAG)->base() + 0xe000, 0);
		}
		else
		{
			memory_configure_bank(machine(), bank_name, 0, 1, machine().region(Z80_TAG)->base() + bank_start, 0);

			if (bank < 5)
			{
				/* bank is RAM */
				memory_install_ram_helper(program, bank_name, bank_start, bank_end);
			}
			else if (bank == 5)
			{
				/* 0x8000-0x9fff */
				if (machine().region("eim")->base())
				{
					/* expansion interface ROM */
					memory_install_rom_helper(program, bank_name, bank_start, bank_end);
					memory_configure_bank(machine(), bank_name, 0, 1, machine().region("eim")->base() + 0x4000, 0);
				}
				else
				{
					/* mirror of 0xa000-0xbfff */
					if (machine().region(Z80_TAG)->base()[0xa001] == 0)
					{
						/* unmapped on the M model */
						memory_install_unmapped(program, bank_name, bank_start, bank_end);
					}
					else
					{
						/* bank is ROM on the A model */
						memory_install_rom_helper(program, bank_name, bank_start, bank_end);
					}

					memory_configure_bank(machine(), bank_name, 0, 1, machine().region(Z80_TAG)->base() + 0xa000, 0);
				}
			}
			else if (bank == 6)
			{
				/* 0xa000-0xbfff */
				if (machine().region(Z80_TAG)->base()[0xa001] == 0)
				{
					/* unmapped on the M model */
					memory_install_unmapped(program, bank_name, bank_start, bank_end);
				}
				else
				{
					/* bank is ROM on the A model */
					memory_install_rom_helper(program, bank_name, bank_start, bank_end);
				}
			}
			else
			{
				/* bank is ROM */
				memory_install_rom_helper(program, bank_name, bank_start, bank_end);
			}
		}

		memory_set_bank(machine(), bank_name, 0);
	}
}

/* Enable/Status */

WRITE8_MEMBER( newbrain_state::enrg1_w )
{
	/*

        bit     signal      description

        0       _CLK        enable frame frequency clock interrupts
        1                   enable user interrupt
        2       TVP         enable video display
        3                   enable V24
        4                   V24 Select Receive Bit 0
        5                   V24 Select Receive Bit 1
        6                   V24 Select Transmit Bit 0
        7                   V24 Select Transmit Bit 1

    */

	m_enrg1 = data;
}

WRITE8_MEMBER( newbrain_state::a_enrg1_w )
{
	/*

        bit     signal      description

        0       _CLK        Clock Enable
        1
        2       TVP         TV Enable
        3       IOPOWER
        4       _CTS        Clear to Send V24
        5       DO          Transmit Data V24
        6
        7       PO          Transmit Data Printer

    */

	m_enrg1 = data;
}

READ8_MEMBER( newbrain_state::ust_r )
{
	/*

        bit     signal      description

        0       variable
        1       variable
        2       MNS         mains present
        3       _USRINT0    user status
        4       _USRINT     user interrupt
        5       _CLKINT     clock interrupt
        6       _ACINT      ACIA interrupt
        7       _COPINT     COP interrupt

    */

	UINT8 data = (m_copint << 7) | (m_aciaint << 6) | (m_clkint << 5) | (m_userint << 4) | 0x04;

	switch ((m_enrg1 & NEWBRAIN_ENRG1_UST_BIT_0_MASK) >> 6)
	{
	case 0:
		// excess, 1=24, 0=4
		if (m_tvctl & NEWBRAIN_VIDEO_32_40)
		{
			data |= 0x01;
		}
		break;

	case 1:
		// characters per line, 1=40, 0=80
		if (m_tvctl & NEWBRAIN_VIDEO_80L)
		{
			data |= 0x01;
		}
		break;

	case 2:
		// tape in
		break;

	case 3:
		// calling indicator
		break;
	}

	switch ((m_enrg1 & NEWBRAIN_ENRG1_UST_BIT_1_MASK) >> 4)
	{
	case 0:
		// PWRUP, if set indicates that power is supplied to Z80 and memory
		if (m_pwrup)
		{
			data |= 0x02;
		}
		break;

	case 1:
		// TVCNSL, if set then processor has video device as primary console output
		if (m_tvcnsl)
		{
			data |= 0x02;
		}
		break;

	case 2:
		// _BEE, if set then processor is Model A type
		if (m_bee)
		{
			data |= 0x02;
		}
		break;

	case 3:
		// _CALLIND, calling indicator
		data |= 0x02;
		break;
	}

	return data;
}

READ8_MEMBER( newbrain_state::a_ust_r )
{
	/*

        bit     signal      description

        0                   +5V
        1       PWRUP
        2
        3
        4
        5       _CLKINT     clock interrupt
        6
        7       _COPINT     COP interrupt

    */

	return (m_copint << 7) | (m_clkint << 5) | (m_pwrup << 1) | 0x01;
}

READ8_MEMBER( newbrain_state::user_r )
{
	/*

        bit     signal      description

        0       RDDK        Received Data V24
        1       _CTSD       _Clear to Send V24
        2
        3
        4
        5       TPIN        Tape in
        6
        7       _CTSP       _Clear to Send Printer

    */

	m_user = 0;

	return 0xff;
}

WRITE8_MEMBER( newbrain_state::user_w )
{
	m_user = data;
}

/* Interrupts */

READ8_MEMBER( newbrain_state::clclk_r )
{
	m_clkint = 1;
	check_interrupt();

	return 0xff;
}

WRITE8_MEMBER( newbrain_state::clclk_w )
{
	m_clkint = 1;
	check_interrupt();
}

READ8_MEMBER( newbrain_state::clusr_r )
{
	m_userint = 1;

	return 0xff;
}

WRITE8_MEMBER( newbrain_state::clusr_w )
{
	m_userint = 1;
}

/* COP420 */

READ8_MEMBER( newbrain_state::cop_l_r )
{
	// connected to the Z80 data bus
	return m_cop_bus;
}

WRITE8_MEMBER( newbrain_state::cop_l_w )
{
	// connected to the Z80 data bus
	m_cop_bus = data;
}

WRITE8_MEMBER( newbrain_state::cop_g_w )
{
	/*

        bit     description

        G0      _COPINT
        G1      _TM1
        G2      not connected
        G3      _TM2

    */

	m_copint = BIT(data, 0);
	check_interrupt();

	/* tape motor enable */

	m_cassette1->change_state(BIT(data,1) ? CASSETTE_MOTOR_DISABLED : CASSETTE_MOTOR_ENABLED, CASSETTE_MASK_MOTOR);
	m_cassette2->change_state(BIT(data,3) ? CASSETTE_MOTOR_DISABLED : CASSETTE_MOTOR_ENABLED, CASSETTE_MASK_MOTOR);
}

READ8_MEMBER( newbrain_state::cop_g_r )
{
	/*

        bit     description

        G0      not connected
        G1      K9
        G2      K7
        G3      K3

    */

	return (BIT(m_keydata, 3) << 3) | (BIT(m_keydata, 0) << 2) | (BIT(m_keydata, 1) << 1);
}

WRITE8_MEMBER( newbrain_state::cop_d_w )
{
	/*
        bit     description

        D0      inverted to K4 -> CD4024 pin 2 (reset)
        D1      TDO
        D2      inverted to K6 -> CD4024 pin 1 (clock), CD4076 pin 7 (clock), inverted to DS8881 pin 3 (enable)
        D3      not connected

    */

	static const char *const keynames[] = {
		"D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7",
		"D8", "D9", "D10", "D11", "D12", "D13", "D14", "D15"
	};

	/* keyboard row reset */

	if (!BIT(data, 0))
	{
		m_keylatch = 0;
	}

	/* tape data output */

	m_cop_tdo = BIT(data, 1);

	m_cassette1->output(m_cop_tdo ? -1.0 : +1.0);
	m_cassette2->output(m_cop_tdo ? -1.0 : +1.0);

	/* keyboard and display clock */

	if (!BIT(data, 2))
	{
		m_keylatch++;

		if (m_keylatch == 16)
		{
			m_keylatch = 0;
		}

		m_keydata = input_port_read(machine(), keynames[m_keylatch]);

		output_set_digit_value(m_keylatch, m_segment_data[m_keylatch]);
	}
}

READ8_MEMBER( newbrain_state::cop_in_r )
{
	/*

        bit     description

        IN0     K8
        IN1     _RD
        IN2     _COP
        IN3     _WR

    */

	return (m_cop_wr << 3) | (m_cop_access << 2) | (m_cop_rd << 1) | BIT(m_keydata, 2);
}

WRITE8_MEMBER( newbrain_state::cop_so_w )
{
	// connected to K1
	m_cop_so = data;
}

WRITE8_MEMBER( newbrain_state::cop_sk_w )
{
	// connected to K2
	m_segment_data[m_keylatch] >>= 1;
	m_segment_data[m_keylatch] = (m_cop_so << 15) | (m_segment_data[m_keylatch] & 0x7fff);
}

READ8_MEMBER( newbrain_state::cop_si_r )
{
	// connected to TDI
	m_cop_tdi = (((m_cassette1)->input() > +1.0) || ((m_cassette2)->input() > +1.0)) ^ m_cop_tdo;

	return m_cop_tdi;
}

/* Video */

void newbrain_state::tvram_w(UINT8 data, int a6)
{
	/* latch video address counter bits A5-A0 */
	m_tvram = (m_tvctl & NEWBRAIN_VIDEO_80L) ? 0x04 : 0x02;

	/* latch video address counter bit A6 */
	m_tvram |= a6 << 6;

	/* latch data to video address counter bits A14-A7 */
	m_tvram = (data << 7);
}

READ8_MEMBER( newbrain_state::tvl_r )
{
	UINT8 data = 0xff;

	tvram_w(data, !offset);

	return data;
}

WRITE8_MEMBER( newbrain_state::tvl_w )
{
	tvram_w(data, !offset);
}

WRITE8_MEMBER( newbrain_state::tvctl_w )
{
	/*

        bit     signal      description

        0       RV          1 reverses video over entire field, ie. black on white
        1       FS          0 generates 128 characters and 128 reverse field characters from 8 bit character code. 1 generates 256 characters from 8 bit character code
        2       32/_40      0 generates 320 or 640 horizontal dots in pixel graphics mode. 1 generates 256 or 512 horizontal dots in pixel graphics mode
        3       UCR         0 selects 256 characters expressed in an 8x10 matrix, and 25 lines (max) displayed. 1 selects 256 characters in an 8x8 matrix, and 31 lines (max) displayed
        4
        5
        6       80L         0 selects 40 character line length. 1 selects 80 character line length
        7

    */

	m_tvctl = data;
}

/* Disc Controller */

WRITE8_MEMBER( newbrain_eim_state::fdc_auxiliary_w )
{
	/*

        bit     description

        0       MOTON
        1       765 RESET
        2       TC
        3
        4
        5       PA15
        6
        7

    */

	floppy_mon_w(m_floppy, !BIT(data, 0));
	floppy_drive_set_ready_state(m_floppy, 1, 0);

	upd765_reset_w(m_fdc, BIT(data, 1));

	upd765_tc_w(m_fdc, BIT(data, 2));
}

READ8_MEMBER( newbrain_eim_state::fdc_control_r )
{
	/*

        bit     description

        0
        1
        2
        3
        4
        5       FDC INT
        6       PAGING
        7       FDC ATT

    */

	return (m_fdc_att << 7) | (m_paging << 6) | (m_fdc_int << 5);
}

READ8_MEMBER( newbrain_eim_state::ust2_r )
{
	/*

        bit     description

        0       RDDK (V24 RxD)
        1       _CTSD (V24 Clear to Send)
        2
        3
        4
        5       TPIN
        6
        7       _CTSP (Printer Clear to Send)

    */

	return 0;
}

#define NEWBRAIN_COPCMD_NULLCOM		0xd0
#define NEWBRAIN_COPCMD_DISPCOM		0xa0
//#define NEWBRAIN_COPCMD_TIMCOM        0x
#define NEWBRAIN_COPCMD_PDNCOM		0xb8
#define NEWBRAIN_COPCMD_TAPECOM		0x80

#define NEWBRAIN_COP_TAPE_RECORD	0x00
#define NEWBRAIN_COP_TAPE_PLAYBK	0x04
#define NEWBRAIN_COP_TAPE_MOTOR1	0x08
#define NEWBRAIN_COP_TAPE_MOTOR2	0x02

#define NEWBRAIN_COP_TIMER0			0x01

#define NEWBRAIN_COP_NO_DATA		0x01
#define NEWBRAIN_COP_BREAK_PRESSED	0x02

#define NEWBRAIN_COP_REGINT			0x00
/*#define NEWBRAIN_COP_CASSERR      0x
#define NEWBRAIN_COP_CASSIN         0x
#define NEWBRAIN_COP_KBD            0x
#define NEWBRAIN_COP_CASSOUT        0x*/

enum
{
	NEWBRAIN_COP_STATE_COMMAND = 0,
	NEWBRAIN_COP_STATE_DATA
};


READ8_MEMBER( newbrain_state::cop_r )
{
	m_copint = 1;
	check_interrupt();

	return m_copdata;
}

WRITE8_MEMBER( newbrain_state::cop_w )
{
	m_copdata = data;

	switch (m_copstate)
	{
	case NEWBRAIN_COP_STATE_COMMAND:
		logerror("COP command %02x\n", data);

		switch (data)
		{
		case NEWBRAIN_COPCMD_NULLCOM:
			break;

		case NEWBRAIN_COPCMD_DISPCOM:
			m_copregint = 0;
			m_copbytes = 18;
			m_copstate = NEWBRAIN_COP_STATE_DATA;

			m_copdata = NEWBRAIN_COP_NO_DATA;
			m_copint = 0;
			check_interrupt();

			break;

#if 0
		case NEWBRAIN_COPCMD_TIMCOM:
			m_copregint = 0;
			m_copbytes = 6;
			m_copstate = NEWBRAIN_COP_STATE_DATA;
			break;
#endif
		case NEWBRAIN_COPCMD_PDNCOM:
			/* power down */
			m_copregint = 0;
			break;

		default:
			if (data & NEWBRAIN_COPCMD_TAPECOM)
			{
				m_copregint = 0;
			}
		}
		break;

	case NEWBRAIN_COP_STATE_DATA:
		logerror("COP data %02x\n", data);
		m_copbytes--;

		if (m_copbytes == 0)
		{
			m_copstate = NEWBRAIN_COP_STATE_COMMAND;
			m_copregint = 1;
		}

		m_copdata = NEWBRAIN_COP_NO_DATA;
		m_copint = 0;
		check_interrupt();

		break;
	}
}

static TIMER_DEVICE_CALLBACK( cop_regint_tick )
{
	newbrain_state *state = timer.machine().driver_data<newbrain_state>();

	if (state->m_copregint)
	{
		logerror("COP REGINT\n");
		state->m_copint = 0;
		state->check_interrupt();
	}
}

/* Expansion Interface Module */

WRITE8_MEMBER( newbrain_eim_state::enrg2_w )
{
	/*

        bit     signal      description

        0       _USERP      0 enables user data bus interrupt and also parallel latched data output (or centronics printer) interrupt
        1       ANP         1 enables ADC conversion complete interrupt and also calling indicator interrupt
        2       MLTMD       1 enables serial receive clock into multiplier input of DAC and signals data terminal not ready
        3       MSPD        1 enables 50K Baud serial data rate to be obtained ie. CTC input clock of 800 kHz. 0 selects xxx.692 kHz
        4       ENOR        1 enables serial receive clock to sound output summer, and also selects serial input from the printer port. 0 selects serial input from the comms port
        5       ANSW        1 enables second bank of 4 analogue inputs (voltage, non-ratiometric), ie. ch4-7, and enabled sound output, 0 selects ch03
        6       ENOT        1 enables serial transmit clock to sound ouput summer, and also selects serial output to the printer port. 0 selects serial output to the comms port
        7                   9th output bit for centronics printer port

    */

	m_enrg2 = data;
}

WRITE8_MEMBER( newbrain_eim_state::pr_w )
{
	/*

        bit     signal      description

        0       HP0
        1       HP1
        2       HP2
        3       HP3
        4       HP4
        5       HP5
        6       HP6
        7       HP11

        HP0-HP2 are decoded to _ROM0..._ROM7 signals
        HP3-HP4 are decoded to _CH0..._CH3 signals

    */

	int page = (BIT(offset, 12) >> 9) | (BIT(offset, 15) >> 13) | (BIT(offset, 14) >> 13) | (BIT(offset, 13) >> 13);
	int bank = (BIT(offset, 11) >> 3) | (data & 0x7f);

	m_pr[page] = bank;

	bankswitch();
}

READ8_MEMBER( newbrain_eim_state::user_r )
{
	m_user = 0xff;

	return 0xff;
}

WRITE8_MEMBER( newbrain_eim_state::user_w )
{
	m_user = data;
}

READ8_MEMBER( newbrain_eim_state::anout_r )
{
	return 0xff;
}

WRITE8_MEMBER( newbrain_eim_state::anout_w )
{
}

READ8_MEMBER( newbrain_eim_state::anin_r )
{
//  int channel = offset & 0x03;

	return 0;
}

WRITE8_MEMBER( newbrain_eim_state::anio_w )
{
//  int channel = offset & 0x03;
}

READ8_MEMBER( newbrain_eim_state::st0_r )
{
	/*

        bit     signal      description

        0                   fixed at 1 - indicates excess of 24 or 48, obsolete
        1       PWRUP       1 indicates power up from 'cold' - necessary in battery machines with power switching
        2                   1 indicates analogue or calling indicator interrupts
        3       _USRINT0    0 indicates centronics printer (latched output data) port interrupt
        4       _USRINT     0 indicates parallel data bus port interrupt
        5       _CLKINT     0 indicates frame frequency clock interrupt
        6       _ACINT      0 indicates ACIA interrupt
        7       _COPINT     0 indicates interrupt from micro-controller COP420M

    */

	return (m_copint << 7) | (m_aciaint << 6) | (m_clkint << 5) | (m_userint << 4) | (m_userint0 << 3) | (m_pwrup) << 1 | 0x01;
}

READ8_MEMBER( newbrain_eim_state::st1_r )
{
	/*

        bit     signal      description

        0
        1
        2       N/_RV       1 selects normal video on power up (white on black), 0 selects reversed video (appears as D0 on the first 200 EI's)
        3       ANCH        1 indicates power is being taken from the mains supply
        4       40/_80      1 indicates that 40 column video is selected on power up. 0 selects 80 column video
        5
        6       TVCNSL      1 indicates that a video display is required on power up
        7

    */

	return (m_tvcnsl << 6) | 0x10 | 0x08 | 0x04;
}

READ8_MEMBER( newbrain_eim_state::st2_r )
{
	/*

        bit     signal      description

        0                   received serial data from communications port
        1                   0 indicates 'clear-to-send' condition at communications port
        2
        3
        4
        5                   logic level tape input
        6
        7                   0 indicates 'clear-to-send' condition at printer port

    */

	return 0;
}

READ8_MEMBER( newbrain_eim_state::usbs_r )
{
	return 0xff;
}

WRITE8_MEMBER( newbrain_eim_state::usbs_w )
{
}

WRITE8_MEMBER( newbrain_eim_state::paging_w )
{
	if (BIT(offset, 8))
	{
		// expansion interface module

		/*

            bit     signal      description

            0       PG          1 enables paging circuits
            1       WPL         unused
            2       A16         1 sets local A16 to 1 (ie. causes second set of 8 page registers to select addressed memory)
            3       _MPM        0 selects multi-processing mode. among other effects this extends the page registers from 8 to 12 bits in length
            4       HISLT       1 isolates the local machine. this is used in multi-processing mode
            5
            6
            7

        */

		m_paging = BIT(data, 0);
		m_a16 = BIT(data, 2);
		m_mpm = BIT(data, 3);
	}
	else if (BIT(offset, 9))
	{
		// disc controller

		/*

            bit     signal      description

            0       PAGING      1 enables paging circuits
            1
            2       HA16        1 sets local A16 to 1 (ie. causes second set of 8 page registers to select addressed memory)
            3       MPM         0 selects multi-processing mode. among other effects this extends the page registers from 8 to 12 bits in length
            4
            5       _FDC RESET
            6
            7       FDC ATT

        */

		m_fdccpu->set_input_line(INPUT_LINE_RESET, BIT(data, 5) ? HOLD_LINE : CLEAR_LINE);

		m_paging = BIT(data, 0);
		m_a16 = BIT(data, 2);
		m_mpm = BIT(data, 3);
		m_fdc_att = BIT(data, 7);
	}
	else if (BIT(offset, 10))
	{
		// network controller
	}
}

/* A/D Converter */

WRITE_LINE_MEMBER( newbrain_eim_state::adc_eoc_w )
{
	m_anint = state;
}

static ADC0808_ANALOG_READ( newbrain_adc_vref_pos_r )
{
	return 5.0;
}

static ADC0808_ANALOG_READ( newbrain_adc_vref_neg_r )
{
	return 0.0;
}

static ADC0808_ANALOG_READ( newbrain_adc_input_r )
{
	return 0.0;
}

static ADC0808_INTERFACE( adc_intf )
{
	DEVCB_DRIVER_LINE_MEMBER(newbrain_eim_state, adc_eoc_w),
	newbrain_adc_vref_pos_r,
	newbrain_adc_vref_neg_r,
	{ newbrain_adc_input_r, newbrain_adc_input_r, newbrain_adc_input_r, newbrain_adc_input_r,
	  newbrain_adc_input_r, newbrain_adc_input_r, newbrain_adc_input_r, newbrain_adc_input_r }
};

/* Memory Maps */

static ADDRESS_MAP_START( newbrain_map, AS_PROGRAM, 8, newbrain_state )
	ADDRESS_MAP_UNMAP_HIGH
	AM_RANGE(0x0000, 0x1fff) AM_RAMBANK("bank1")
	AM_RANGE(0x2000, 0x3fff) AM_RAMBANK("bank2")
	AM_RANGE(0x4000, 0x5fff) AM_RAMBANK("bank3")
	AM_RANGE(0x6000, 0x7fff) AM_RAMBANK("bank4")
	AM_RANGE(0x8000, 0x9fff) AM_RAMBANK("bank5")
	AM_RANGE(0xa000, 0xbfff) AM_RAMBANK("bank6")
	AM_RANGE(0xc000, 0xdfff) AM_RAMBANK("bank7")
	AM_RANGE(0xe000, 0xffff) AM_RAMBANK("bank8")
ADDRESS_MAP_END

static ADDRESS_MAP_START( newbrain_ei_io_map, AS_IO, 8, newbrain_eim_state )
	ADDRESS_MAP_UNMAP_HIGH
	AM_RANGE(0x00, 0x00) AM_MIRROR(0xff00) AM_READWRITE_BASE(newbrain_state, clusr_r, clusr_w)
	AM_RANGE(0x01, 0x01) AM_MIRROR(0xff00) AM_WRITE(enrg2_w)
	AM_RANGE(0x02, 0x02) AM_MIRROR(0xff00) AM_MASK(0xff00) AM_WRITE(pr_w)
	AM_RANGE(0x03, 0x03) AM_MIRROR(0xff00) AM_READWRITE(user_r, user_w)
	AM_RANGE(0x04, 0x04) AM_MIRROR(0xff00) AM_READWRITE_BASE(newbrain_state, clclk_r, clclk_w)
	AM_RANGE(0x05, 0x05) AM_MIRROR(0xff00) AM_READWRITE(anout_r, anout_w)
	AM_RANGE(0x06, 0x06) AM_MIRROR(0xff00) AM_READWRITE_BASE(newbrain_state, cop_r, cop_w)
	AM_RANGE(0x07, 0x07) AM_MIRROR(0xff00) AM_WRITE_BASE(newbrain_state, enrg1_w)
	AM_RANGE(0x08, 0x09) AM_MIRROR(0xff02) AM_READWRITE_BASE(newbrain_state, tvl_r, tvl_w)
	AM_RANGE(0x0c, 0x0c) AM_MIRROR(0xff03) AM_WRITE_BASE(newbrain_state, tvctl_w)
	AM_RANGE(0x10, 0x13) AM_MIRROR(0xff00) AM_READWRITE(anin_r, anio_w)
	AM_RANGE(0x14, 0x14) AM_MIRROR(0xff00) AM_READ(st0_r)
	AM_RANGE(0x15, 0x15) AM_MIRROR(0xff00) AM_READ(st1_r)
	AM_RANGE(0x16, 0x16) AM_MIRROR(0xff00) AM_READ(st2_r)
	AM_RANGE(0x17, 0x17) AM_MIRROR(0xff00) AM_READWRITE(usbs_r, usbs_w)
	AM_RANGE(0x18, 0x18) AM_MIRROR(0xff00) AM_DEVREADWRITE(MC6850_TAG, acia6850_device, status_read, control_write)
	AM_RANGE(0x19, 0x19) AM_MIRROR(0xff00) AM_DEVREADWRITE(MC6850_TAG, acia6850_device, data_read, data_write)
	AM_RANGE(0x1c, 0x1f) AM_MIRROR(0xff00) AM_DEVREADWRITE_LEGACY(Z80CTC_TAG, z80ctc_r, z80ctc_w)
	AM_RANGE(0xff, 0xff) AM_MIRROR(0xff00) AM_MASK(0xff00) AM_WRITE(paging_w)
ADDRESS_MAP_END

static ADDRESS_MAP_START( newbrain_a_io_map, AS_IO, 8, newbrain_state )
	ADDRESS_MAP_UNMAP_HIGH
	AM_RANGE(0x00, 0x00) AM_MIRROR(0xffc0) AM_READWRITE(clusr_r, clusr_w)
	AM_RANGE(0x03, 0x03) AM_MIRROR(0xffc0) AM_WRITE(user_w)
	AM_RANGE(0x04, 0x04) AM_MIRROR(0xffc0) AM_READWRITE(clclk_r, clclk_w)
	AM_RANGE(0x06, 0x06) AM_MIRROR(0xffc0) AM_READWRITE(cop_r, cop_w)
	AM_RANGE(0x07, 0x07) AM_MIRROR(0xffc0) AM_WRITE(a_enrg1_w)
	AM_RANGE(0x08, 0x09) AM_MIRROR(0xffc2) AM_READWRITE(tvl_r, tvl_w)
	AM_RANGE(0x0c, 0x0c) AM_MIRROR(0xffc3) AM_WRITE(tvctl_w)
	AM_RANGE(0x14, 0x14) AM_MIRROR(0xffc3) AM_READ(a_ust_r)
	AM_RANGE(0x16, 0x16) AM_MIRROR(0xffc0) AM_READ(user_r)
ADDRESS_MAP_END

static ADDRESS_MAP_START( newbrain_cop_io_map, AS_IO, 8, newbrain_state )
	AM_RANGE(COP400_PORT_L, COP400_PORT_L) AM_READWRITE(cop_l_r, cop_l_w)
	AM_RANGE(COP400_PORT_G, COP400_PORT_G) AM_READWRITE(cop_g_r, cop_g_w)
	AM_RANGE(COP400_PORT_D, COP400_PORT_D) AM_WRITE(cop_d_w)
	AM_RANGE(COP400_PORT_IN, COP400_PORT_IN) AM_READ(cop_in_r)
	AM_RANGE(COP400_PORT_SK, COP400_PORT_SK) AM_WRITE(cop_sk_w)
	AM_RANGE(COP400_PORT_SIO, COP400_PORT_SIO) AM_READWRITE(cop_si_r, cop_so_w)
	AM_RANGE(COP400_PORT_CKO, COP400_PORT_CKO) AM_READNOP
ADDRESS_MAP_END

static ADDRESS_MAP_START( newbrain_fdc_map, AS_PROGRAM, 8, newbrain_eim_state )
	ADDRESS_MAP_UNMAP_HIGH
	AM_RANGE(0x0000, 0x1fff) AM_ROM
ADDRESS_MAP_END

static ADDRESS_MAP_START( newbrain_fdc_io_map, AS_IO, 8, newbrain_eim_state )
	ADDRESS_MAP_UNMAP_HIGH
	ADDRESS_MAP_GLOBAL_MASK(0xff)
	AM_RANGE(0x00, 0x00) AM_DEVREAD_LEGACY(UPD765_TAG, upd765_status_r)
	AM_RANGE(0x01, 0x01) AM_DEVREADWRITE_LEGACY(UPD765_TAG, upd765_data_r, upd765_data_w)
	AM_RANGE(0x20, 0x20) AM_WRITE(fdc_auxiliary_w)
	AM_RANGE(0x40, 0x40) AM_READ(fdc_control_r)
ADDRESS_MAP_END

/* Input Ports */

static INPUT_PORTS_START( newbrain )
	PORT_START("D0")
	PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("STOP") PORT_CODE(KEYCODE_END) PORT_CHAR(UCHAR_MAMEKEY(END))
	PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNUSED )

	PORT_START("D1")
	PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME(UTF8_DOWN) PORT_CODE(KEYCODE_DOWN) PORT_CHAR(UCHAR_MAMEKEY(DOWN))
	PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME(UTF8_RIGHT) PORT_CODE(KEYCODE_RIGHT) PORT_CHAR(UCHAR_MAMEKEY(RIGHT))
	PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME(UTF8_LEFT) PORT_CODE(KEYCODE_LEFT) PORT_CHAR(UCHAR_MAMEKEY(LEFT))
	PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME(UTF8_UP) PORT_CODE(KEYCODE_UP) PORT_CHAR(UCHAR_MAMEKEY(UP))

	PORT_START("D2")
	PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_U) PORT_CHAR('u') PORT_CHAR('U')
	PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_8) PORT_CHAR('8')
	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_J) PORT_CHAR('j') PORT_CHAR('J')

	PORT_START("D3")
	PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_I) PORT_CHAR('i') PORT_CHAR('I')
	PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_9) PORT_CHAR('9')
	PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_6) PORT_CHAR('6') PORT_CHAR('&')
	PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_N) PORT_CHAR('n') PORT_CHAR('N')

	PORT_START("D4")
	PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Y) PORT_CHAR('y') PORT_CHAR('Y')
	PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_0) PORT_CHAR('0')
	PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_5) PORT_CHAR('5') PORT_CHAR('%')
	PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_M) PORT_CHAR('m') PORT_CHAR('M')

	PORT_START("D5")
	PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_O) PORT_CHAR('o') PORT_CHAR('O')
	PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_MINUS) PORT_CHAR('(') PORT_CHAR('[')
	PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_4) PORT_CHAR('4') PORT_CHAR('$')
	PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COMMA) PORT_CHAR(',') PORT_CHAR('<')

	PORT_START("D6")
	PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_L) PORT_CHAR('l') PORT_CHAR('L')
	PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR(')') PORT_CHAR(']')
	PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_3) PORT_CHAR('3') PORT_CHAR('#')
	PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_STOP) PORT_CHAR('.') PORT_CHAR('>')

	PORT_START("D7")
	PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_COLON) PORT_CHAR(';') PORT_CHAR(':')
	PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("* \xC2\xA3") PORT_CODE(KEYCODE_CLOSEBRACE) PORT_CHAR('*') PORT_CHAR(0x00A3)
	PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_2) PORT_CHAR('2') PORT_CHAR('"')
	PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_B) PORT_CHAR('b') PORT_CHAR('B')

	PORT_START("D8")
	PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_H) PORT_CHAR('h') PORT_CHAR('H')
	PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("VIDEO TEXT") PORT_CODE(KEYCODE_RALT) PORT_CHAR(UCHAR_MAMEKEY(RALT)) // Vd
	PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_1) PORT_CHAR('1') PORT_CHAR('!')
	PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_V) PORT_CHAR('v') PORT_CHAR('V')

	PORT_START("D9")
	PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_G) PORT_CHAR('g') PORT_CHAR('G')
	PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_P) PORT_CHAR('p') PORT_CHAR('P')
	PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_T) PORT_CHAR('t') PORT_CHAR('T')
	PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_C) PORT_CHAR('c') PORT_CHAR('C')

	PORT_START("D10")
	PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_F) PORT_CHAR('f') PORT_CHAR('F')
	PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_EQUALS) PORT_CHAR('=') PORT_CHAR('@')
	PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_R) PORT_CHAR('r') PORT_CHAR('R')
	PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_X) PORT_CHAR('x') PORT_CHAR('X')

	PORT_START("D11")
	PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_D) PORT_CHAR('d') PORT_CHAR('D')
	PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_OPENBRACE) PORT_CHAR('-') PORT_CHAR('\\')
	PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_E) PORT_CHAR('e') PORT_CHAR('E')
	PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Z) PORT_CHAR('z') PORT_CHAR('Z')

	PORT_START("D12")
	PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_S) PORT_CHAR('s') PORT_CHAR('S')
	PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_QUOTE) PORT_CHAR('+') PORT_CHAR('^')
	PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_W) PORT_CHAR('w') PORT_CHAR('W')
	PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("INSERT") PORT_CODE(KEYCODE_INSERT) PORT_CHAR(UCHAR_MAMEKEY(INSERT))

	PORT_START("D13")
	PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_A) PORT_CHAR('a') PORT_CHAR('A')
	PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("NEW LINE") PORT_CODE(KEYCODE_ENTER) PORT_CHAR(13) // NL
	PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_Q) PORT_CHAR('q') PORT_CHAR('Q')
	PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_K) PORT_CHAR('k') PORT_CHAR('K')

	PORT_START("D14")
	PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_CODE(KEYCODE_SLASH) PORT_CHAR('/') PORT_CHAR('?')
	PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNUSED )
	PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("SPACE") PORT_CODE(KEYCODE_SPACE) PORT_CHAR(' ')
	PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("HOME") PORT_CODE(KEYCODE_HOME) PORT_CHAR(UCHAR_MAMEKEY(HOME)) // CH

	PORT_START("D15")
	PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("SHIFT") PORT_CODE(KEYCODE_LSHIFT) PORT_CODE(KEYCODE_RSHIFT) PORT_CHAR(UCHAR_SHIFT_1) // SH
	PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("GRAPHICS") PORT_CODE(KEYCODE_LALT) PORT_CHAR(UCHAR_MAMEKEY(LALT)) // GR
	PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("REPEAT") // RPT
	PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_KEYBOARD ) PORT_NAME("CONTROL") PORT_CODE(KEYCODE_LCONTROL) PORT_CHAR(UCHAR_MAMEKEY(LCONTROL)) // GL
INPUT_PORTS_END

/* Machine Initialization */

READ_LINE_MEMBER( newbrain_eim_state::acia_rx )
{
	return m_acia_rxd;
}

WRITE_LINE_MEMBER( newbrain_eim_state::acia_tx )
{
	m_acia_txd = state;
}

WRITE_LINE_MEMBER( newbrain_eim_state::acia_interrupt )
{
	m_aciaint = state;
}

static ACIA6850_INTERFACE( acia_intf )
{
	0,
	0,
	DEVCB_DRIVER_LINE_MEMBER(newbrain_eim_state, acia_rx),
	DEVCB_DRIVER_LINE_MEMBER(newbrain_eim_state, acia_tx),
	DEVCB_NULL,
	DEVCB_NULL,
	DEVCB_NULL,
	DEVCB_DRIVER_LINE_MEMBER(newbrain_eim_state, acia_interrupt)
};

WRITE_LINE_MEMBER( newbrain_eim_state::fdc_interrupt )
{
	m_fdc_int = state;
}

static const upd765_interface fdc_intf =
{
	DEVCB_DRIVER_LINE_MEMBER(newbrain_eim_state, fdc_interrupt),
	DEVCB_NULL,
	NULL,
	UPD765_RDY_PIN_NOT_CONNECTED,
	{FLOPPY_0,FLOPPY_1, NULL, NULL}
};

WRITE_LINE_MEMBER( newbrain_eim_state::ctc_z0_w )
{
	/* connected to the ACIA receive clock */
	if (state) m_acia->rx_clock_in();
}

WRITE_LINE_MEMBER( newbrain_eim_state::ctc_z1_w )
{
	/* connected to the ACIA transmit clock */
	if (state) m_acia->tx_clock_in();
}

WRITE_LINE_MEMBER( newbrain_eim_state::ctc_z2_w )
{
	/* connected to CTC channel 0/1 clock inputs */
	z80ctc_trg0_w(m_ctc, state);
	z80ctc_trg1_w(m_ctc, state);
}

static Z80CTC_INTERFACE( newbrain_ctc_intf )
{
	0,              		/* timer disables */
	DEVCB_NULL,				/* interrupt handler */
	DEVCB_DRIVER_LINE_MEMBER(newbrain_eim_state, ctc_z0_w),	/* ZC/TO0 callback */
	DEVCB_DRIVER_LINE_MEMBER(newbrain_eim_state, ctc_z1_w),	/* ZC/TO1 callback */
	DEVCB_DRIVER_LINE_MEMBER(newbrain_eim_state, ctc_z2_w)	/* ZC/TO2 callback */
};

static TIMER_DEVICE_CALLBACK( ctc_c2_tick )
{
	newbrain_eim_state *state = timer.machine().driver_data<newbrain_eim_state>();

	z80ctc_trg2_w(state->m_ctc, 1);
	z80ctc_trg2_w(state->m_ctc, 0);
}

inline int newbrain_state::get_reset_t()
{
	return RES_K(220) * CAP_U(10) * 1000; // t = R128 * C125 = 2.2s
}

static TIMER_CALLBACK( reset_tick )
{
	newbrain_state *state = machine.driver_data<newbrain_state>();

	state->m_maincpu->set_input_line(INPUT_LINE_RESET, CLEAR_LINE);
	state->m_copcpu->set_input_line(INPUT_LINE_RESET, CLEAR_LINE);
}

inline int newbrain_state::get_pwrup_t()
{
	return RES_K(560) * CAP_U(10) * 1000; // t = R129 * C127 = 5.6s
}

static TIMER_CALLBACK( pwrup_tick )
{
	newbrain_state *state = machine.driver_data<newbrain_state>();

	state->m_pwrup = 0;
	state->bankswitch();
}

void newbrain_state::machine_start()
{
	m_copregint = 1;

	/* allocate reset timer */
	m_reset_timer = machine().scheduler().timer_alloc(FUNC(reset_tick));
	m_reset_timer->adjust(attotime::from_usec(get_reset_t()));

	/* allocate power up timer */
	m_pwrup_timer = machine().scheduler().timer_alloc(FUNC(pwrup_tick));
	m_pwrup_timer->adjust(attotime::from_usec(get_pwrup_t()));

	/* initialize variables */
	m_pwrup = 1;
	m_userint = 1;
	m_userint0 = 1;
	m_clkint = 1;
	m_aciaint = 1;
	m_copint = 1;
	m_bee = 1;
	m_tvcnsl = 1;

	/* set up memory banking */
	bankswitch();

	/* register for state saving */
	save_item(NAME(m_pwrup));
	save_item(NAME(m_userint));
	save_item(NAME(m_userint0));
	save_item(NAME(m_clkint));
	save_item(NAME(m_aciaint));
	save_item(NAME(m_copint));
	save_item(NAME(m_anint));
	save_item(NAME(m_bee));
	save_item(NAME(m_enrg1));
	save_item(NAME(m_enrg2));
	save_item(NAME(m_cop_bus));
	save_item(NAME(m_cop_so));
	save_item(NAME(m_cop_tdo));
	save_item(NAME(m_cop_tdi));
	save_item(NAME(m_cop_rd));
	save_item(NAME(m_cop_wr));
	save_item(NAME(m_cop_access));
	save_item(NAME(m_keylatch));
	save_item(NAME(m_keydata));
	save_item(NAME(m_user));
}

void newbrain_eim_state::machine_start()
{
	newbrain_state::machine_start();

	/* allocate expansion RAM */
	m_eim_ram = auto_alloc_array(machine(), UINT8, NEWBRAIN_EIM_RAM_SIZE);

	/* register for state saving */
	save_pointer(NAME(m_eim_ram), NEWBRAIN_EIM_RAM_SIZE);
	save_item(NAME(m_mpm));
	save_item(NAME(m_a16));
	save_item(NAME(m_pr));
	save_item(NAME(m_fdc_int));
	save_item(NAME(m_fdc_att));
	save_item(NAME(m_paging));
}

void newbrain_state::machine_reset()
{
	m_reset_timer->adjust(attotime::from_msec(get_reset_t()));
}

static INTERRUPT_GEN( newbrain_interrupt )
{
	newbrain_state *state = device->machine().driver_data<newbrain_state>();

	if (!(state->m_enrg1 & NEWBRAIN_ENRG1_CLK))
	{
		state->m_clkint = 0;
		state->check_interrupt();
	}
}

static COP400_INTERFACE( newbrain_cop_intf )
{
	COP400_CKI_DIVISOR_16, // ???
	COP400_CKO_OSCILLATOR_OUTPUT,
	COP400_MICROBUS_ENABLED
};

/* Machine Drivers */

static const cassette_interface newbrain_cassette_interface =
{
	cassette_default_formats,
	NULL,
	(cassette_state)(CASSETTE_STOPPED | CASSETTE_MOTOR_ENABLED | CASSETTE_SPEAKER_MUTED),
	NULL,
	NULL
};

/* F4 Character Displayer */
static const gfx_layout newbrain_charlayout =
{
	8, 10,					/* 8 x 10 characters */
	256,					/* 256 characters */
	1,					/* 1 bits per pixel */
	{ 0 },					/* no bitplanes */
	/* x offsets */
	{ 0, 1, 2, 3, 4, 5, 6, 7 },
	/* y offsets */
	{ 0*256*8, 1*256*8, 2*256*8, 3*256*8, 4*256*8, 5*256*8, 6*256*8, 7*256*8, 8*256*8, 9*256*8, 10*256*8, 11*256*8, 12*256*8, 13*256*8, 14*256*8, 15*256*8 },
	8					/* every char takes 16 x 1 bytes */
};

static GFXDECODE_START( newbrain )
	GFXDECODE_ENTRY( "chargen", 0x0000, newbrain_charlayout, 0, 1 )
GFXDECODE_END

static MACHINE_CONFIG_START( newbrain_a, newbrain_state )
	// basic system hardware
	MCFG_CPU_ADD(Z80_TAG, Z80, XTAL_16MHz/8)
	MCFG_CPU_PROGRAM_MAP(newbrain_map)
	MCFG_CPU_IO_MAP(newbrain_a_io_map)
	MCFG_CPU_VBLANK_INT(SCREEN_TAG, newbrain_interrupt)

	MCFG_CPU_ADD(COP420_TAG, COP420, XTAL_16MHz/8) // COP420-GUW/N
	MCFG_CPU_IO_MAP(newbrain_cop_io_map)
	MCFG_CPU_CONFIG(newbrain_cop_intf)

	MCFG_GFXDECODE(newbrain)

	MCFG_TIMER_ADD_PERIODIC("cop_regint", cop_regint_tick, attotime::from_usec(12500)) // HACK

	// video hardware
	MCFG_FRAGMENT_ADD(newbrain_video)

	// devices
	MCFG_CASSETTE_ADD(CASSETTE_TAG, newbrain_cassette_interface)
	MCFG_CASSETTE_ADD(CASSETTE2_TAG, newbrain_cassette_interface)

	// internal ram
	MCFG_RAM_ADD(RAM_TAG)
	MCFG_RAM_DEFAULT_SIZE("32K")
MACHINE_CONFIG_END

static LEGACY_FLOPPY_OPTIONS_START(newbrain)
	// 180K img
LEGACY_FLOPPY_OPTIONS_END

static const floppy_interface newbrain_floppy_interface =
{
	DEVCB_NULL,
	DEVCB_NULL,
	DEVCB_NULL,
	DEVCB_NULL,
	DEVCB_NULL,
	FLOPPY_STANDARD_5_25_DSDD,
	LEGACY_FLOPPY_OPTIONS_NAME(newbrain),
	NULL,
	NULL
};

static MACHINE_CONFIG_DERIVED_CLASS( newbrain_eim, newbrain_a, newbrain_eim_state )
	// basic system hardware
	MCFG_CPU_MODIFY(Z80_TAG)
	MCFG_CPU_IO_MAP(newbrain_ei_io_map)

	MCFG_CPU_ADD(FDC_Z80_TAG, Z80, XTAL_4MHz)
	MCFG_CPU_PROGRAM_MAP(newbrain_fdc_map)
	MCFG_CPU_IO_MAP(newbrain_fdc_io_map)

	// devices
	MCFG_Z80CTC_ADD(Z80CTC_TAG, XTAL_16MHz/8, newbrain_ctc_intf)
	MCFG_TIMER_ADD_PERIODIC("z80ctc_c2", ctc_c2_tick, attotime::from_hz(XTAL_16MHz/4/13))
	MCFG_ADC0808_ADD(ADC0809_TAG, 500000, adc_intf)
	MCFG_ACIA6850_ADD(MC6850_TAG, acia_intf)
	MCFG_UPD765A_ADD(UPD765_TAG, fdc_intf)
	MCFG_LEGACY_FLOPPY_2_DRIVES_ADD(newbrain_floppy_interface)

	// internal ram
	MCFG_RAM_MODIFY(RAM_TAG)
	MCFG_RAM_DEFAULT_SIZE("96K")
MACHINE_CONFIG_END

/* ROMs */

ROM_START( newbrain )
	ROM_REGION( 0x10000, Z80_TAG, 0 )
	ROM_DEFAULT_BIOS( "rom20" )

	ROM_SYSTEM_BIOS( 0, "issue1", "Issue 1 (v?)" )
	ROMX_LOAD( "aben.ic6",     0xa000, 0x2000, CRC(308f1f72) SHA1(a6fd9945a3dca47636887da2125fde3f9b1d4e25), ROM_BIOS(1) )
	ROMX_LOAD( "cd iss 1.ic7", 0xc000, 0x2000, CRC(6b4d9429) SHA1(ef688be4e75aced61f487c928258c8932a0ae00a), ROM_BIOS(1) )
	ROMX_LOAD( "ef iss 1.ic8", 0xe000, 0x2000, CRC(20dd0b49) SHA1(74b517ca223cefb588e9f49e72ff2d4f1627efc6), ROM_BIOS(1) )

	ROM_SYSTEM_BIOS( 1, "issue2", "Issue 2 (v1.9)" )
	ROMX_LOAD( "aben19.ic6",   0xa000, 0x2000, CRC(d0283eb1) SHA1(351d248e69a77fa552c2584049006911fb381ff0), ROM_BIOS(2) )
	ROMX_LOAD( "cdi2.ic7",     0xc000, 0x2000, CRC(6b4d9429) SHA1(ef688be4e75aced61f487c928258c8932a0ae00a), ROM_BIOS(2) )
	ROMX_LOAD( "ef iss 1.ic8", 0xe000, 0x2000, CRC(20dd0b49) SHA1(74b517ca223cefb588e9f49e72ff2d4f1627efc6), ROM_BIOS(2) )

	ROM_SYSTEM_BIOS( 2, "issue3", "Issue 3 (v1.91)" )
	ROMX_LOAD( "aben191.ic6",  0xa000, 0x2000, CRC(b7be8d89) SHA1(cce8d0ae7aa40245907ea38b7956c62d039d45b7), ROM_BIOS(3) )
	ROMX_LOAD( "cdi3.ic7",	   0xc000, 0x2000, CRC(6b4d9429) SHA1(ef688be4e75aced61f487c928258c8932a0ae00a), ROM_BIOS(3) )
	ROMX_LOAD( "ef iss 1.ic8", 0xe000, 0x2000, CRC(20dd0b49) SHA1(74b517ca223cefb588e9f49e72ff2d4f1627efc6), ROM_BIOS(3) )

	ROM_SYSTEM_BIOS( 3, "series2", "Series 2 (v?)" )
	ROMX_LOAD( "abs2.ic6",	   0xa000, 0x2000, CRC(9a042acb) SHA1(80d83a2ea3089504aa68b6cf978d80d296cd9bda), ROM_BIOS(4) )
	ROMX_LOAD( "cds2.ic7",	   0xc000, 0x2000, CRC(6b4d9429) SHA1(ef688be4e75aced61f487c928258c8932a0ae00a), ROM_BIOS(4) )
	ROMX_LOAD( "efs2.ic8",	   0xe000, 0x2000, CRC(b222d798) SHA1(c0c816b4d4135b762f2c5f1b24209d0096f22e56), ROM_BIOS(4) )

	ROM_SYSTEM_BIOS( 4, "rom20", "? (v2.0)" )
	ROMX_LOAD( "aben20.rom",   0xa000, 0x2000, CRC(3d76d0c8) SHA1(753b4530a518ad832e4b81c4e5430355ba3f62e0), ROM_BIOS(5) )
	ROMX_LOAD( "cd20tci.rom",  0xc000, 0x4000, CRC(f65b2350) SHA1(1ada7fbf207809537ec1ffb69808524300622ada), ROM_BIOS(5) )

	ROM_REGION( 0x400, COP420_TAG, 0 )
	ROM_LOAD( "cop420.419", 0x000, 0x400, NO_DUMP )

	ROM_REGION( 0x1000, "chargen", ROMREGION_ERASE00 )
	ROM_LOAD( "char eprom iss 1.ic453", 0x0000, 0x0a01, BAD_DUMP CRC(46ecbc65) SHA1(3fe064d49a4de5e3b7383752e98ad35a674e26dd) ) // 8248R7
ROM_END

#define rom_newbraina rom_newbrain

ROM_START( newbraineim )
	ROM_REGION( 0x10000, Z80_TAG, 0 )
	ROM_DEFAULT_BIOS( "rom20" )

	ROM_SYSTEM_BIOS( 0, "issue1", "Issue 1 (v?)" )
	ROMX_LOAD( "aben.ic6",     0xa000, 0x2000, CRC(308f1f72) SHA1(a6fd9945a3dca47636887da2125fde3f9b1d4e25), ROM_BIOS(1) )
	ROMX_LOAD( "cd iss 1.ic7", 0xc000, 0x2000, CRC(6b4d9429) SHA1(ef688be4e75aced61f487c928258c8932a0ae00a), ROM_BIOS(1) )
	ROMX_LOAD( "ef iss 1.ic8", 0xe000, 0x2000, CRC(20dd0b49) SHA1(74b517ca223cefb588e9f49e72ff2d4f1627efc6), ROM_BIOS(1) )

	ROM_SYSTEM_BIOS( 1, "issue2", "Issue 2 (v1.9)" )
	ROMX_LOAD( "aben19.ic6",   0xa000, 0x2000, CRC(d0283eb1) SHA1(351d248e69a77fa552c2584049006911fb381ff0), ROM_BIOS(2) )
	ROMX_LOAD( "cdi2.ic7",     0xc000, 0x2000, CRC(6b4d9429) SHA1(ef688be4e75aced61f487c928258c8932a0ae00a), ROM_BIOS(2) )
	ROMX_LOAD( "ef iss 1.ic8", 0xe000, 0x2000, CRC(20dd0b49) SHA1(74b517ca223cefb588e9f49e72ff2d4f1627efc6), ROM_BIOS(2) )

	ROM_SYSTEM_BIOS( 2, "issue3", "Issue 3 (v1.91)" )
	ROMX_LOAD( "aben191.ic6",  0xa000, 0x2000, CRC(b7be8d89) SHA1(cce8d0ae7aa40245907ea38b7956c62d039d45b7), ROM_BIOS(3) )
	ROMX_LOAD( "cdi3.ic7",	   0xc000, 0x2000, CRC(6b4d9429) SHA1(ef688be4e75aced61f487c928258c8932a0ae00a), ROM_BIOS(3) )
	ROMX_LOAD( "ef iss 1.ic8", 0xe000, 0x2000, CRC(20dd0b49) SHA1(74b517ca223cefb588e9f49e72ff2d4f1627efc6), ROM_BIOS(3) )

	ROM_SYSTEM_BIOS( 3, "series2", "Series 2 (v?)" )
	ROMX_LOAD( "abs2.ic6",	   0xa000, 0x2000, CRC(9a042acb) SHA1(80d83a2ea3089504aa68b6cf978d80d296cd9bda), ROM_BIOS(4) )
	ROMX_LOAD( "cds2.ic7",	   0xc000, 0x2000, CRC(6b4d9429) SHA1(ef688be4e75aced61f487c928258c8932a0ae00a), ROM_BIOS(4) )
	ROMX_LOAD( "efs2.ic8",	   0xe000, 0x2000, CRC(b222d798) SHA1(c0c816b4d4135b762f2c5f1b24209d0096f22e56), ROM_BIOS(4) )

	ROM_SYSTEM_BIOS( 4, "rom20", "? (v2.0)" )
	ROMX_LOAD( "aben20.rom",   0xa000, 0x2000, CRC(3d76d0c8) SHA1(753b4530a518ad832e4b81c4e5430355ba3f62e0), ROM_BIOS(5) )
	ROMX_LOAD( "cd20tci.rom",  0xc000, 0x4000, CRC(f65b2350) SHA1(1ada7fbf207809537ec1ffb69808524300622ada), ROM_BIOS(5) )

	ROM_REGION( 0x400, COP420_TAG, 0 )
	ROM_LOAD( "cop420.419",   0x000, 0x400, NO_DUMP )

	ROM_REGION( 0x1000, "chargen", 0 )
	ROM_LOAD( "char eprom iss 1.ic453", 0x0000, 0x0a01, BAD_DUMP CRC(46ecbc65) SHA1(3fe064d49a4de5e3b7383752e98ad35a674e26dd) ) // 8248R7

	ROM_REGION( 0x10000, "eim", 0 ) // Expansion Interface Module
	ROM_LOAD( "e415-2.rom", 0x4000, 0x2000, CRC(5b0e390c) SHA1(0f99cae57af2e64f3f6b02e5325138d6ba015e72) )
	ROM_LOAD( "e415-3.rom", 0x4000, 0x2000, CRC(2f88bae5) SHA1(04e03f230f4b368027442a7c2084dae877f53713) ) // 18/8/83.aci
	ROM_LOAD( "e416-3.rom", 0x6000, 0x2000, CRC(8b5099d8) SHA1(19b0cfce4c8b220eb1648b467f94113bafcb14e0) ) // 10/8/83.mtv
	ROM_LOAD( "e417-2.rom", 0x8000, 0x2000, CRC(6a7afa20) SHA1(f90db4f8318777313a862b3d5bab83c2fd260010) )

	ROM_REGION( 0x10000, FDC_Z80_TAG, 0 ) // Floppy Disk Controller
	ROM_LOAD( "d413-2.rom", 0x0000, 0x2000, CRC(097591f1) SHA1(c2aa1d27d4f3a24ab0c8135df746a4a44201a7f4) )
	ROM_LOAD( "d417-1.rom", 0x0000, 0x2000, CRC(40fad31c) SHA1(5137be4cc026972c0ffd4fa6990e8583bdfce163) )
	ROM_LOAD( "d417-2.rom", 0x0000, 0x2000, CRC(e8bda8b9) SHA1(c85a76a5ff7054f4ef4a472ce99ebaed1abd269c) )
ROM_END

ROM_START( newbrainmd )
	ROM_REGION( 0x10000, Z80_TAG, 0 )
	ROM_LOAD( "cdmd.rom", 0xc000, 0x2000, CRC(6b4d9429) SHA1(ef688be4e75aced61f487c928258c8932a0ae00a) )
	ROM_LOAD( "efmd.rom", 0xe000, 0x2000, CRC(20dd0b49) SHA1(74b517ca223cefb588e9f49e72ff2d4f1627efc6) )

	ROM_REGION( 0x400, COP420_TAG, 0 )
	ROM_LOAD( "cop420.419", 0x000, 0x400, NO_DUMP )

	ROM_REGION( 0x1000, "chargen", 0 )
	ROM_LOAD( "char eprom iss 1.ic453", 0x0000, 0x0a01, BAD_DUMP CRC(46ecbc65) SHA1(3fe064d49a4de5e3b7383752e98ad35a674e26dd) ) // 8248R7
ROM_END

/* System Drivers */

//    YEAR  NAME        PARENT      COMPAT  MACHINE         INPUT       INIT    COMPANY                         FULLNAME        FLAGS
COMP( 1981, newbrain,	0,          0,      newbrain_a,     newbrain,   0,      "Grundy Business Systems Ltd",	"NewBrain AD",	GAME_NOT_WORKING | GAME_NO_SOUND)
COMP( 1981, newbraineim,newbrain,   0,      newbrain_eim,   newbrain,   0,      "Grundy Business Systems Ltd",	"NewBrain AD with Expansion Interface",	GAME_NOT_WORKING | GAME_NO_SOUND )
COMP( 1981, newbraina,	newbrain,   0,      newbrain_a,     newbrain,   0,      "Grundy Business Systems Ltd",	"NewBrain A",	GAME_NOT_WORKING | GAME_NO_SOUND)
COMP( 1981, newbrainmd,	newbrain,   0,      newbrain_a,     newbrain,   0,      "Grundy Business Systems Ltd",	"NewBrain MD",	GAME_NOT_WORKING | GAME_NO_SOUND )
